From a1d73c3ecb72ec39dee4ddef380c458ad48caee6 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Mon, 26 Sep 2022 16:42:08 +0200 Subject: [PATCH 01/24] Initial implementation of ets compiler Signed-off-by: Robert Fancsik --- BUILD.gn | 211 +- CMakeLists.txt | 218 +- aot/main.cpp | 16 +- aot/options.cpp | 9 +- aot/options.h | 5 + binder/ASBinder.cpp | 19 + binder/ASBinder.h | 46 + binder/JSBinder.cpp | 19 + binder/JSBinder.h | 34 + binder/STSBinder.cpp | 550 + binder/STSBinder.h | 129 + binder/TSBinder.cpp | 19 + binder/TSBinder.h | 44 + binder/TypedBinder.cpp | 77 + binder/TypedBinder.h | 36 + binder/binder.cpp | 367 +- binder/binder.h | 116 +- binder/declaration.h | 32 +- binder/recordTable.cpp | 97 + binder/recordTable.h | 184 + binder/scope.cpp | 19 +- binder/scope.h | 70 +- binder/variable.h | 18 +- binder/variableFlags.h | 15 +- checker/ASchecker.cpp | 32 + checker/ASchecker.h | 44 + checker/JSchecker.cpp | 35 + checker/JSchecker.h | 44 + checker/STSchecker.cpp | 93 + checker/STSchecker.h | 376 + checker/TSchecker.cpp | 51 + typescript/checker.h => checker/TSchecker.h | 279 +- .../typeRelation.cpp => checker/checker.cpp | 73 +- checker/checker.h | 269 + .../core => checker}/checkerContext.cpp | 0 {typescript/core => checker}/checkerContext.h | 37 +- checker/sts/aliveAnalyzer.cpp | 425 + checker/sts/aliveAnalyzer.h | 87 + checker/sts/arithmetic.cpp | 327 + checker/sts/arithmetic.h | 217 + checker/sts/baseAnalyzer.cpp | 62 + checker/sts/baseAnalyzer.h | 91 + checker/sts/boxingConverter.cpp | 76 + checker/sts/boxingConverter.h | 44 + checker/sts/function.cpp | 487 + checker/sts/helpers.cpp | 624 ++ checker/sts/narrowingConverter.cpp | 19 + checker/sts/narrowingConverter.h | 123 + checker/sts/narrowingWideningConverter.cpp | 19 + checker/sts/narrowingWideningConverter.h | 37 + checker/sts/object.cpp | 794 ++ checker/sts/primitiveWrappers.cpp | 19 + checker/sts/primitiveWrappers.h | 58 + checker/sts/typeConverter.cpp | 19 + checker/sts/typeConverter.h | 45 + checker/sts/typeCreation.cpp | 277 + checker/sts/typeRelationContext.cpp | 125 + checker/sts/typeRelationContext.h | 165 + checker/sts/unboxingConverter.cpp | 55 + checker/sts/unboxingConverter.h | 48 + checker/sts/wideningConverter.cpp | 19 + checker/sts/wideningConverter.h | 195 + .../ts}/binaryLikeExpression.cpp | 29 +- .../ts}/destructuringContext.cpp | 31 +- .../ts}/destructuringContext.h | 44 +- {typescript/core => checker/ts}/function.cpp | 194 +- {typescript/core => checker/ts}/helpers.cpp | 126 +- {typescript/core => checker/ts}/object.cpp | 110 +- .../core => checker/ts}/typeCreation.cpp | 70 +- .../ts}/typeElaborationContext.cpp | 8 +- .../ts}/typeElaborationContext.h | 18 +- {typescript/core => checker/ts}/util.cpp | 53 +- .../types/globalTypesHolder.cpp | 132 +- .../types/globalTypesHolder.h | 53 +- {typescript => checker}/types/signature.cpp | 27 +- {typescript => checker}/types/signature.h | 95 +- checker/types/sts/byteType.cpp | 39 + checker/types/sts/byteType.h | 54 + checker/types/sts/charType.cpp | 39 + checker/types/sts/charType.h | 54 + checker/types/sts/doubleType.cpp | 37 + checker/types/sts/doubleType.h | 54 + checker/types/sts/floatType.cpp | 40 + checker/types/sts/floatType.h | 54 + checker/types/sts/intType.cpp | 40 + checker/types/sts/intType.h | 54 + checker/types/sts/longType.cpp | 40 + checker/types/sts/longType.h | 54 + checker/types/sts/shortType.cpp | 39 + checker/types/sts/shortType.h | 54 + checker/types/sts/stsArrayType.cpp | 66 + checker/types/sts/stsArrayType.h | 48 + checker/types/sts/stsBooleanType.cpp | 33 + checker/types/sts/stsBooleanType.h | 53 + checker/types/sts/stsFunctionType.cpp | 63 + checker/types/sts/stsFunctionType.h | 80 + checker/types/sts/stsObjectType.cpp | 248 + checker/types/sts/stsObjectType.h | 313 + checker/types/sts/stsStringType.cpp | 35 + checker/types/sts/stsStringType.h | 63 + checker/types/sts/stsTypeParameter.cpp | 33 + checker/types/sts/stsTypeParameter.h | 62 + checker/types/sts/stsTypeReference.cpp | 85 + checker/types/sts/stsTypeReference.h | 69 + checker/types/sts/stsVoidType.cpp | 33 + .../types/sts/stsVoidType.h | 47 +- checker/types/sts/types.h | 38 + checker/types/sts/wildcardType.cpp | 38 + checker/types/sts/wildcardType.h | 38 + .../types => checker/types/ts}/anyType.cpp | 0 .../types => checker/types/ts}/anyType.h | 8 +- .../types => checker/types/ts}/arrayType.cpp | 2 +- .../types => checker/types/ts}/arrayType.h | 6 +- .../types/ts}/bigintLiteralType.cpp | 0 .../types/ts}/bigintLiteralType.h | 6 +- .../types => checker/types/ts}/bigintType.cpp | 0 .../types => checker/types/ts}/bigintType.h | 6 +- .../types/ts}/booleanLiteralType.cpp | 0 .../types/ts}/booleanLiteralType.h | 6 +- .../types/ts}/booleanType.cpp | 0 .../types => checker/types/ts}/booleanType.h | 6 +- .../types/ts}/constructorType.cpp | 2 +- .../types/ts}/constructorType.h | 4 +- .../types => checker/types/ts}/elementFlags.h | 4 +- .../types/ts}/enumLiteralType.cpp | 2 +- .../types/ts}/enumLiteralType.h | 6 +- .../types => checker/types/ts}/enumType.cpp | 0 .../types => checker/types/ts}/enumType.h | 6 +- .../types/ts}/functionType.cpp | 2 +- .../types => checker/types/ts}/functionType.h | 4 +- .../types => checker/types/ts}/indexInfo.cpp | 0 .../types => checker/types/ts}/indexInfo.h | 6 +- .../types/ts}/interfaceType.cpp | 4 +- .../types/ts}/interfaceType.h | 4 +- .../types => checker/types/ts}/neverType.cpp | 0 .../types => checker/types/ts}/neverType.h | 6 +- .../types/ts}/nonPrimitiveType.cpp | 0 .../types/ts}/nonPrimitiveType.h | 6 +- .../types => checker/types/ts}/nullType.cpp | 0 .../types => checker/types/ts}/nullType.h | 6 +- .../types/ts}/numberLiteralType.cpp | 2 +- .../types/ts}/numberLiteralType.h | 6 +- .../types => checker/types/ts}/numberType.cpp | 2 +- .../types => checker/types/ts}/numberType.h | 6 +- .../types/ts}/objectDescriptor.cpp | 4 +- .../types/ts}/objectDescriptor.h | 4 +- .../types/ts}/objectLiteralType.cpp | 6 +- .../types/ts}/objectLiteralType.h | 4 +- .../types => checker/types/ts}/objectType.cpp | 8 +- .../types => checker/types/ts}/objectType.h | 8 +- .../types/ts}/stringLiteralType.cpp | 0 .../types/ts}/stringLiteralType.h | 6 +- .../types => checker/types/ts}/stringType.cpp | 0 .../types => checker/types/ts}/stringType.h | 6 +- .../types => checker/types/ts}/tupleType.cpp | 4 +- .../types => checker/types/ts}/tupleType.h | 10 +- .../types/ts}/typeParameter.cpp | 0 .../types/ts}/typeParameter.h | 6 +- .../types/ts}/typeReference.cpp | 0 .../types/ts}/typeReference.h | 8 +- .../types => checker/types/ts}/types.h | 6 +- .../types/ts}/undefinedType.cpp | 0 .../types/ts}/undefinedType.h | 6 +- .../types => checker/types/ts}/unionType.cpp | 2 +- .../types => checker/types/ts}/unionType.h | 6 +- .../types/ts}/unknownType.cpp | 0 .../types => checker/types/ts}/unknownType.h | 6 +- .../types => checker/types/ts}/voidType.cpp | 0 .../types => checker/types/ts}/voidType.h | 6 +- {typescript => checker}/types/type.cpp | 28 +- {typescript => checker}/types/type.h | 57 +- {typescript => checker}/types/typeFacts.h | 4 +- checker/types/typeFlag.h | 123 + checker/types/typeMapping.h | 66 + .../types/typeRelation.cpp | 40 +- {typescript => checker}/types/typeRelation.h | 139 +- compiler/base/catchTable.cpp | 4 +- compiler/base/catchTable.h | 6 +- compiler/base/condition.cpp | 73 + compiler/base/condition.h | 9 + compiler/base/destructuring.cpp | 10 +- compiler/base/literals.h | 2 +- compiler/base/lreference.cpp | 159 +- compiler/base/lreference.h | 92 +- compiler/base/optionalChain.cpp | 2 +- compiler/core/JSemitter.cpp | 101 + compiler/core/JSemitter.h | 58 + compiler/core/STSGen.cpp | 1191 ++ compiler/core/STSGen.h | 637 ++ compiler/core/STSemitter.cpp | 584 + compiler/core/STSemitter.h | 90 + compiler/core/STSfunction.cpp | 159 + compiler/core/STSfunction.h | 43 + compiler/core/codeGen.cpp | 196 + compiler/core/codeGen.h | 208 + compiler/core/compileJob.cpp | 49 + compiler/core/compileJob.h | 72 + compiler/core/compileQueue.cpp | 48 +- compiler/core/compileQueue.h | 34 +- compiler/core/compilerContext.cpp | 9 - compiler/core/compilerContext.h | 49 +- compiler/core/compilerImpl.cpp | 129 +- compiler/core/compilerImpl.h | 26 +- compiler/core/dynamicContext.cpp | 71 +- compiler/core/dynamicContext.h | 97 +- compiler/core/emitter.cpp | 131 +- compiler/core/emitter.h | 58 +- compiler/core/envScope.cpp | 7 +- compiler/core/envScope.h | 4 +- compiler/core/function.cpp | 8 +- compiler/core/labelTarget.cpp | 6 +- compiler/core/labelTarget.h | 4 +- compiler/core/pandagen.cpp | 345 +- compiler/core/pandagen.h | 197 +- .../{inlineCache.h => programElement.cpp} | 21 +- compiler/core/programElement.h | 41 + compiler/core/regAllocator.cpp | 60 +- compiler/core/regAllocator.h | 28 +- compiler/core/regScope.cpp | 111 +- compiler/core/regScope.h | 13 +- compiler/core/regSpiller.cpp | 94 + compiler/core/regSpiller.h | 120 + compiler/core/switchBuilder.cpp | 57 - compiler/core/switchBuilder.h | 68 +- ...{inlineCache.cpp => targetTypeContext.cpp} | 23 +- compiler/core/targetTypeContext.h | 44 + compiler/core/vReg.cpp | 19 + compiler/core/vReg.h | 146 + compiler/function/functionBuilder.cpp | 2 +- compiler/scripts/signatures.rb | 71 + compiler/scripts/signatures.yaml | 226 + compiler/templates/isa.h.erb | 5 +- compiler/templates/signatures.h.erb | 59 + es2panda.cpp | 39 +- es2panda.h | 31 +- ir/as/namedType.cpp | 13 +- ir/as/namedType.h | 11 +- ir/as/prefixAssertionExpression.cpp | 8 +- ir/as/prefixAssertionExpression.h | 9 +- ir/astDump.cpp | 35 +- ir/astDump.h | 33 +- ir/astNode.cpp | 42 + ir/astNode.h | 196 +- ir/astNodeMapping.h | 267 +- ir/base/catchClause.cpp | 56 +- ir/base/catchClause.h | 30 +- ir/base/classDefinition.cpp | 82 +- ir/base/classDefinition.h | 157 +- ir/base/classElement.cpp | 16 +- ir/base/classElement.h | 25 +- ir/base/classProperty.cpp | 49 +- ir/base/classProperty.h | 25 +- ir/base/classStaticBlock.cpp | 45 +- ir/base/classStaticBlock.h | 17 +- ir/base/decorator.cpp | 7 +- ir/base/decorator.h | 12 +- ir/base/metaProperty.cpp | 9 +- ir/base/metaProperty.h | 12 +- ir/base/methodDefinition.cpp | 80 +- ir/base/methodDefinition.h | 24 +- ir/base/property.cpp | 7 +- ir/base/property.h | 12 +- ir/base/scriptFunction.cpp | 17 +- ir/base/scriptFunction.h | 97 +- ir/base/spreadElement.cpp | 13 +- ir/base/spreadElement.h | 28 +- ir/base/templateElement.cpp | 7 +- ir/base/templateElement.h | 12 +- ir/{ts => base}/tsIndexSignature.cpp | 19 +- ir/{ts => base}/tsIndexSignature.h | 28 +- ir/{ts => base}/tsMethodSignature.cpp | 14 +- ir/{ts => base}/tsMethodSignature.h | 28 +- ir/{ts => base}/tsPropertySignature.cpp | 11 +- ir/{ts => base}/tsPropertySignature.h | 32 +- ir/{ts => base}/tsSignatureDeclaration.cpp | 19 +- ir/{ts => base}/tsSignatureDeclaration.h | 28 +- ir/expression.h | 44 +- ir/expressions/arrayExpression.cpp | 43 +- ir/expressions/arrayExpression.h | 41 +- ir/expressions/arrowFunctionExpression.cpp | 11 +- ir/expressions/arrowFunctionExpression.h | 12 +- ir/expressions/assignmentExpression.cpp | 98 +- ir/expressions/assignmentExpression.h | 24 +- ir/expressions/awaitExpression.cpp | 9 +- ir/expressions/awaitExpression.h | 12 +- ir/expressions/binaryExpression.cpp | 69 +- ir/expressions/binaryExpression.h | 25 +- ir/expressions/callExpression.cpp | 82 +- ir/expressions/callExpression.h | 33 +- ir/expressions/chainExpression.cpp | 13 +- ir/expressions/chainExpression.h | 14 +- ir/expressions/classExpression.cpp | 7 +- ir/expressions/classExpression.h | 12 +- ir/expressions/conditionalExpression.cpp | 45 +- ir/expressions/conditionalExpression.h | 14 +- ir/expressions/directEvalExpression.h | 4 - ir/expressions/functionExpression.cpp | 17 +- ir/expressions/functionExpression.h | 18 +- ir/expressions/identifier.cpp | 36 +- ir/expressions/identifier.h | 55 +- ir/expressions/importExpression.cpp | 7 +- ir/expressions/importExpression.h | 12 +- ir/expressions/literal.h | 9 - ir/expressions/literals/bigIntLiteral.cpp | 9 +- ir/expressions/literals/bigIntLiteral.h | 12 +- ir/expressions/literals/booleanLiteral.cpp | 17 +- ir/expressions/literals/booleanLiteral.h | 13 +- ir/expressions/literals/charLiteral.cpp | 50 + ir/expressions/literals/charLiteral.h | 50 + ir/expressions/literals/nullLiteral.cpp | 17 +- ir/expressions/literals/nullLiteral.h | 13 +- ir/expressions/literals/numberLiteral.cpp | 86 +- ir/expressions/literals/numberLiteral.h | 39 +- ir/expressions/literals/regExpLiteral.cpp | 9 +- ir/expressions/literals/regExpLiteral.h | 12 +- ir/expressions/literals/stringLiteral.cpp | 17 +- ir/expressions/literals/stringLiteral.h | 14 +- ir/expressions/memberExpression.cpp | 97 +- ir/expressions/memberExpression.h | 44 +- ir/expressions/newExpression.cpp | 15 +- ir/expressions/newExpression.h | 13 +- ir/expressions/objectExpression.cpp | 41 +- ir/expressions/objectExpression.h | 32 +- ir/expressions/omittedExpression.cpp | 9 +- ir/expressions/omittedExpression.h | 12 +- ir/expressions/sequenceExpression.cpp | 9 +- ir/expressions/sequenceExpression.h | 12 +- ir/expressions/superExpression.cpp | 22 +- ir/expressions/superExpression.h | 13 +- ir/expressions/taggedTemplateExpression.cpp | 13 +- ir/expressions/taggedTemplateExpression.h | 12 +- ir/expressions/templateLiteral.cpp | 9 +- ir/expressions/templateLiteral.h | 12 +- ir/expressions/thisExpression.cpp | 42 +- ir/expressions/thisExpression.h | 13 +- ir/expressions/unaryExpression.cpp | 74 +- ir/expressions/unaryExpression.h | 7 +- ir/expressions/updateExpression.cpp | 51 +- ir/expressions/updateExpression.h | 12 +- ir/expressions/yieldExpression.cpp | 9 +- ir/expressions/yieldExpression.h | 9 +- ir/irnode.cpp | 6 - ir/irnode.h | 34 +- ir/module/exportAllDeclaration.cpp | 7 +- ir/module/exportAllDeclaration.h | 12 +- ir/module/exportDefaultDeclaration.cpp | 7 +- ir/module/exportDefaultDeclaration.h | 17 +- ir/module/exportNamedDeclaration.cpp | 13 +- ir/module/exportNamedDeclaration.h | 28 +- ir/module/exportSpecifier.cpp | 7 +- ir/module/exportSpecifier.h | 12 +- ir/module/importDeclaration.cpp | 13 +- ir/module/importDeclaration.h | 13 +- ir/module/importDefaultSpecifier.cpp | 7 +- ir/module/importDefaultSpecifier.h | 12 +- ir/module/importNamespaceSpecifier.cpp | 7 +- ir/module/importNamespaceSpecifier.h | 12 +- ir/module/importSpecifier.cpp | 18 +- ir/module/importSpecifier.h | 29 +- ir/statement.h | 23 +- ir/statements/assertStatement.cpp | 109 + ir/statements/assertStatement.h | 56 + ir/statements/blockStatement.cpp | 26 +- ir/statements/blockStatement.h | 18 +- ir/statements/breakStatement.cpp | 25 +- ir/statements/breakStatement.h | 19 +- ir/statements/classDeclaration.cpp | 17 +- ir/statements/classDeclaration.h | 19 +- ir/statements/continueStatement.cpp | 25 +- ir/statements/continueStatement.h | 19 +- ir/statements/debuggerStatement.cpp | 7 +- ir/statements/debuggerStatement.h | 12 +- ir/statements/deferStatement.cpp | 49 + ir/statements/deferStatement.h | 45 + ir/statements/doWhileStatement.cpp | 57 +- ir/statements/doWhileStatement.h | 13 +- ir/statements/emptyStatement.cpp | 7 +- ir/statements/emptyStatement.h | 12 +- ir/statements/expressionStatement.cpp | 12 +- ir/statements/expressionStatement.h | 18 +- ir/statements/forInStatement.cpp | 11 +- ir/statements/forInStatement.h | 12 +- ir/statements/forOfStatement.cpp | 17 +- ir/statements/forOfStatement.h | 13 +- ir/statements/forUpdateStatement.cpp | 60 +- ir/statements/forUpdateStatement.h | 13 +- ir/statements/functionDeclaration.cpp | 20 +- ir/statements/functionDeclaration.h | 18 +- ir/statements/ifStatement.cpp | 53 +- ir/statements/ifStatement.h | 13 +- ir/statements/labelledStatement.cpp | 45 +- ir/statements/labelledStatement.h | 15 +- ir/statements/loopStatement.h | 17 +- ir/statements/panicStatement.cpp | 74 + ir/statements/panicStatement.h | 45 + ir/statements/returnStatement.cpp | 73 +- ir/statements/returnStatement.h | 18 +- ir/statements/switchCaseStatement.cpp | 7 +- ir/statements/switchCaseStatement.h | 17 +- ir/statements/switchStatement.cpp | 60 +- ir/statements/switchStatement.h | 13 +- ir/statements/throwStatement.cpp | 16 +- ir/statements/throwStatement.h | 13 +- ir/statements/trapStatement.cpp | 119 + ir/statements/trapStatement.h | 58 + ir/statements/tryStatement.cpp | 79 +- ir/statements/tryStatement.h | 8 +- ir/statements/variableDeclaration.cpp | 21 +- ir/statements/variableDeclaration.h | 13 +- ir/statements/variableDeclarator.cpp | 66 +- ir/statements/variableDeclarator.h | 19 +- ir/statements/whileStatement.cpp | 52 +- ir/statements/whileStatement.h | 13 +- ir/sts/stsClassLiteral.cpp | 62 + ir/sts/stsClassLiteral.h | 39 + ir/sts/stsNewArrayInstanceExpression.cpp | 65 + ir/sts/stsNewArrayInstanceExpression.h | 45 + ir/sts/stsNewClassInstanceExpression.cpp | 98 + ir/sts/stsNewClassInstanceExpression.h | 75 + .../stsNewMultiDimArrayInstanceExpression.cpp | 66 + .../stsNewMultiDimArrayInstanceExpression.h | 61 + ir/sts/stsPackageDeclaration.cpp | 48 + ir/sts/stsPackageDeclaration.h | 41 + ir/sts/stsPrimitiveType.cpp | 88 + ir/sts/stsPrimitiveType.h | 47 + ir/sts/stsScript.cpp | 20 + ir/sts/stsScript.h | 49 + ir/sts/stsTryExpression.cpp | 51 + ir/sts/stsTryExpression.h | 39 + ir/sts/stsTypeReference.cpp | 85 + ir/sts/stsTypeReference.h | 49 + ir/sts/stsTypeReferencePart.cpp | 79 + ir/sts/stsTypeReferencePart.h | 73 + ir/sts/stsWildcardType.cpp | 69 + ir/sts/stsWildcardType.h | 72 + ir/ts/tsAnyKeyword.cpp | 11 +- ir/ts/tsAnyKeyword.h | 14 +- ir/ts/tsArrayType.cpp | 21 +- ir/ts/tsArrayType.h | 21 +- ir/ts/tsAsExpression.cpp | 61 +- ir/ts/tsAsExpression.h | 28 +- ir/ts/tsBigintKeyword.cpp | 11 +- ir/ts/tsBigintKeyword.h | 14 +- ir/ts/tsBooleanKeyword.cpp | 11 +- ir/ts/tsBooleanKeyword.h | 14 +- ir/ts/tsClassImplements.cpp | 7 +- ir/ts/tsClassImplements.h | 26 +- ir/ts/tsConditionalType.cpp | 9 +- ir/ts/tsConditionalType.h | 14 +- ir/ts/tsConstructorType.cpp | 17 +- ir/ts/tsConstructorType.h | 20 +- ir/ts/tsEnumDeclaration.cpp | 41 +- ir/ts/tsEnumDeclaration.h | 16 +- ir/ts/tsEnumMember.cpp | 7 +- ir/ts/tsEnumMember.h | 12 +- ir/ts/tsExternalModuleReference.cpp | 7 +- ir/ts/tsExternalModuleReference.h | 12 +- ir/ts/tsFunctionType.cpp | 17 +- ir/ts/tsFunctionType.h | 20 +- ir/ts/tsImportEqualsDeclaration.cpp | 7 +- ir/ts/tsImportEqualsDeclaration.h | 12 +- ir/ts/tsImportType.cpp | 9 +- ir/ts/tsImportType.h | 14 +- ir/ts/tsIndexedAccessType.cpp | 23 +- ir/ts/tsIndexedAccessType.h | 24 +- ir/ts/tsInferType.cpp | 9 +- ir/ts/tsInferType.h | 14 +- ir/ts/tsInterfaceBody.cpp | 7 +- ir/ts/tsInterfaceBody.h | 28 +- ir/ts/tsInterfaceDeclaration.cpp | 26 +- ir/ts/tsInterfaceDeclaration.h | 60 +- ir/ts/tsInterfaceHeritage.cpp | 9 +- ir/ts/tsInterfaceHeritage.h | 23 +- ir/ts/tsIntersectionType.cpp | 16 +- ir/ts/tsIntersectionType.h | 15 +- ir/ts/tsLiteralType.cpp | 18 +- ir/ts/tsLiteralType.h | 14 +- ir/ts/tsMappedType.cpp | 10 +- ir/ts/tsMappedType.h | 20 +- ir/ts/tsModuleBlock.cpp | 7 +- ir/ts/tsModuleBlock.h | 12 +- ir/ts/tsModuleDeclaration.cpp | 7 +- ir/ts/tsModuleDeclaration.h | 12 +- ir/ts/tsNamedTupleMember.cpp | 7 +- ir/ts/tsNamedTupleMember.h | 29 +- ir/ts/tsNeverKeyword.cpp | 11 +- ir/ts/tsNeverKeyword.h | 14 +- ir/ts/tsNonNullExpression.cpp | 7 +- ir/ts/tsNonNullExpression.h | 12 +- ir/ts/tsNullKeyword.cpp | 11 +- ir/ts/tsNullKeyword.h | 14 +- ir/ts/tsNumberKeyword.cpp | 11 +- ir/ts/tsNumberKeyword.h | 14 +- ir/ts/tsObjectKeyword.cpp | 11 +- ir/ts/tsObjectKeyword.h | 14 +- ir/ts/tsParameterProperty.cpp | 7 +- ir/ts/tsParameterProperty.h | 12 +- ir/ts/tsParenthesizedType.cpp | 20 +- ir/ts/tsParenthesizedType.h | 18 +- ir/ts/tsQualifiedName.cpp | 77 +- ir/ts/tsQualifiedName.h | 22 +- ir/ts/tsStringKeyword.cpp | 11 +- ir/ts/tsStringKeyword.h | 14 +- ir/ts/tsThisType.cpp | 9 +- ir/ts/tsThisType.h | 14 +- ir/ts/tsTupleType.cpp | 28 +- ir/ts/tsTupleType.h | 20 +- ir/ts/tsTypeAliasDeclaration.cpp | 10 +- ir/ts/tsTypeAliasDeclaration.h | 25 +- ir/ts/tsTypeAssertion.cpp | 8 +- ir/ts/tsTypeAssertion.h | 24 +- ir/ts/tsTypeLiteral.cpp | 21 +- ir/ts/tsTypeLiteral.h | 20 +- ir/ts/tsTypeOperator.cpp | 9 +- ir/ts/tsTypeOperator.h | 20 +- ir/ts/tsTypeParameter.cpp | 8 +- ir/ts/tsTypeParameter.h | 27 +- ir/ts/tsTypeParameterDeclaration.cpp | 7 +- ir/ts/tsTypeParameterDeclaration.h | 12 +- ir/ts/tsTypeParameterInstantiation.cpp | 9 +- ir/ts/tsTypeParameterInstantiation.h | 20 +- ir/ts/tsTypePredicate.cpp | 10 +- ir/ts/tsTypePredicate.h | 20 +- ir/ts/tsTypeQuery.cpp | 19 +- ir/ts/tsTypeQuery.h | 14 +- ir/ts/tsTypeReference.cpp | 34 +- ir/ts/tsTypeReference.h | 16 +- ir/ts/tsUndefinedKeyword.cpp | 11 +- ir/ts/tsUndefinedKeyword.h | 14 +- ir/ts/tsUnionType.cpp | 21 +- ir/ts/tsUnionType.h | 20 +- ir/ts/tsUnknownKeyword.cpp | 11 +- ir/ts/tsUnknownKeyword.h | 14 +- ir/ts/tsVoidKeyword.cpp | 11 +- ir/ts/tsVoidKeyword.h | 14 +- ir/typeNode.h | 17 +- lexer/ASLexer.cpp | 25 + lexer/ASLexer.h | 37 + lexer/STSLexer.cpp | 188 + lexer/STSLexer.h | 52 + lexer/TSLexer.cpp | 25 + lexer/TSLexer.h | 37 + lexer/keywordString.h | 1 + lexer/keywords.cpp | 74 + lexer/keywordsBase.h | 64 + lexer/keywordsUtil.cpp | 17 +- lexer/keywordsUtil.h | 70 +- lexer/lexer.cpp | 375 +- lexer/lexer.h | 183 +- lexer/scripts/keywords.rb | 279 +- lexer/scripts/keywords.yaml | 481 + lexer/templates/keywords.h.erb | 113 +- lexer/token/number.cpp | 56 + lexer/token/number.h | 117 + lexer/token/sourceLocation.cpp | 7 +- lexer/token/token.cpp | 15 +- lexer/token/token.h | 16 +- lexer/token/tokenType.h | 18 + parser/ASparser.cpp | 1721 +++ parser/ASparser.h | 95 + parser/JSparser.cpp | 19 + parser/JSparser.h | 31 + parser/STSparser.cpp | 2169 ++++ parser/STSparser.h | 183 + parser/TSparser.cpp | 2970 +++++ parser/TSparser.h | 148 + parser/TypedParser.cpp | 1507 +++ parser/TypedParser.h | 155 + parser/context/classPrivateContext.cpp | 9 +- parser/context/classPrivateContext.h | 3 +- parser/context/parserContext.h | 45 +- parser/expressionParser.cpp | 906 +- parser/parserFlags.h | 11 +- parser/parserImpl.cpp | 3306 +----- parser/parserImpl.h | 544 +- parser/program/program.cpp | 62 +- parser/program/program.h | 99 +- parser/statementParser.cpp | 1155 +- stdlib/ets/io/PrintStream.sts | 35 + stdlib/ets/io/Serializable.sts | 5 + stdlib/ets/lang/AbstractStringBuilder.sts | 43 + stdlib/ets/lang/AssertionError.sts | 21 + stdlib/ets/lang/Boolean.sts | 20 + stdlib/ets/lang/Char.sts | 20 + stdlib/ets/lang/Class.sts | 8 + stdlib/ets/lang/Double.sts | 20 + stdlib/ets/lang/Error.sts | 20 + stdlib/ets/lang/Exception.sts | 23 + stdlib/ets/lang/Float.sts | 20 + stdlib/ets/lang/Integer.sts | 24 + stdlib/ets/lang/Long.sts | 20 + stdlib/ets/lang/Math.sts | 52 + stdlib/ets/lang/NullPointerException.sts | 21 + stdlib/ets/lang/Object.sts | 23 + stdlib/ets/lang/RuntimeException.sts | 22 + stdlib/ets/lang/Short.sts | 20 + stdlib/ets/lang/String.sts | 21 + stdlib/ets/lang/StringBuilder.sts | 28 + stdlib/ets/lang/System.sts | 21 + stdlib/ets/lang/Throwable.sts | 37 + ...ctMethodDeclaredInParentClass-expected.txt | 2525 +++++ .../abstractMethodDeclaredInParentClass.sts | 43 + ...actNewClassInstanceExpression-expected.txt | 1070 ++ .../abstractNewClassInstanceExpression.sts | 19 + .../interfaceMethodNotOverridden-expected.txt | 524 + .../sts/interfaceMethodNotOverridden.sts | 9 + .../sts/invalidPrivateAcces-expected.txt | 980 ++ .../sts/invalidPrivateAccess1-expected.txt | 748 ++ test/compiler/sts/invalidPrivateAccess1.sts | 10 + .../sts/invalidPrivateAccess2-expected.txt | 594 + test/compiler/sts/invalidPrivateAccess2.sts | 11 + .../sts/invalidPrivateAccess3-expected.txt | 999 ++ test/compiler/sts/invalidPrivateAccess3.sts | 21 + .../sts/invalidPrivateAccess4-expected.txt | 521 + test/compiler/sts/invalidPrivateAccess4.sts | 9 + .../sts/invalidPrivateAccess5-expected.txt | 980 ++ test/compiler/sts/invalidPrivateAccess5.sts | 13 + .../sts/invalidPrivateAccess6-expected.txt | 1536 +++ test/compiler/sts/invalidPrivateAccess6.sts | 24 + ...odOverrideCovariantReturnType-expected.txt | 1916 ++++ .../sts/methodOverrideCovariantReturnType.sts | 31 + ...hodOverrideDifferentSignature-expected.txt | 1261 +++ .../sts/methodOverrideDifferentSignature.sts | 23 + ...methodOverrideWithoutModifier-expected.txt | 587 + .../sts/methodOverrideWithoutModifier.sts | 11 + .../sts/multipleMethodOverride-expected.txt | 1047 ++ test/compiler/sts/multipleMethodOverride.sts | 22 + ...overrideModifierNotOverriding-expected.txt | 632 ++ .../sts/overrideModifierNotOverriding.sts | 11 + .../sts/privateMethodOverride-expected.txt | 587 + test/compiler/sts/privateMethodOverride.sts | 9 + ...staticInitializerInInnerClass-expected.txt | 686 ++ .../sts/staticInitializerInInnerClass.sts | 18 + ...perReferenceFromStaticContext-expected.txt | 592 + .../sts/superReferenceFromStaticContext.sts | 9 + ...hisReferenceFromStaticContext-expected.txt | 415 + .../sts/thisReferenceFromStaticContext.sts | 7 + ...VarReferenceFromStaticContext-expected.txt | 564 + .../sts/typeVarReferenceFromStaticContext.sts | 5 + test/compiler/ts/test-interface4-expected.txt | 2 +- test/compiler/ts/test-interface5-expected.txt | 2 +- test/compiler/ts/test-interface7-expected.txt | 2 +- .../ts/test-type-literal4-expected.txt | 2 +- .../ts/test-type-literal5-expected.txt | 2 +- .../ts/test-type-literal7-expected.txt | 2 +- test/parser/as/test_class_method-expected.txt | 9 +- .../as/test_class_property-expected.txt | 7 +- test/parser/as/test_decorators1-expected.txt | 14 +- test/parser/as/test_decorators2-expected.txt | 2 +- test/parser/as/test_decorators3-expected.txt | 2 +- test/parser/as/test_decorators4-expected.txt | 21 +- test/parser/as/test_interface1-expected.txt | 2 +- test/parser/as/test_interface3-expected.txt | 2 +- test/parser/as/test_interface4-expected.txt | 2 +- test/parser/as/test_interface5-expected.txt | 2 +- .../js/module-test-export-all-expected.txt | 71 + ...xport-all.js => module-test-export-all.js} | 0 ...module-test-export-named-decl-expected.txt | 767 ++ ...cl.js => module-test-export-named-decl.js} | 0 .../js/module-test-import-decl-expected.txt | 1 + ...ort-decl.js => module-test-import-decl.js} | 0 ...module-test-import-expression-expected.txt | 154 + ...on.js => module-test-import-expression.js} | 0 .../js/module-test-import-meta-expected.txt | 1 + ...ort-meta.js => module-test-import-meta.js} | 0 .../module-test-imported-decl1-expected.txt | 1 + ...decl1.js => module-test-imported-decl1.js} | 0 ...st-one-default-export-allowed-expected.txt | 1 + ...module-test-one-default-export-allowed.js} | 0 .../js/test-class-async-method-expected.txt | 5 +- .../js/test-class-definition-expected.txt | 2 - .../js/test-class-expression-expected.txt | 10 +- .../js/test-class-static-block-expected.txt | 10 +- .../js/test-class-static-block6-expected.txt | 2 +- test/parser/js/test-export-all-expected.txt | 1 - .../js/test-export-named-decl-expected.txt | 1 - ....txt => test-function-decl-1-expected.txt} | 76 +- ...nction-decl.js => test-function-decl-1.js} | 2 - .../js/test-function-decl-2-expected.txt | 1 + test/parser/js/test-function-decl-2.js | 16 + test/parser/js/test-import-decl-expected.txt | 1 - .../js/test-import-expression-expected.txt | 1 - test/parser/js/test-import-meta-expected.txt | 1 - .../js/test-imported-decl1-expected.txt | 1 - .../js/test-member-expression-1-expected.txt | 2 +- ...st-one-default-export-allowed-expected.txt | 1 - .../parser/js/test-private-field-expected.txt | 10 +- test/parser/js/this-expression-expected.txt | 2 +- .../parser/sts/AccessBinaryTrees-expected.txt | 4486 ++++++++ test/parser/sts/AccessBinaryTrees.sts | 81 + test/parser/sts/AccessFannkuch-expected.txt | 4829 ++++++++ test/parser/sts/AccessFannkuch.sts | 93 + test/parser/sts/AccessNBody-expected.txt | 1 + test/parser/sts/AccessNBody.sts | 221 + test/parser/sts/AccessNSieve-expected.txt | 2684 +++++ test/parser/sts/AccessNSieve.sts | 57 + .../sts/Bitops3BitBitsInByte-expected.txt | 2131 ++++ test/parser/sts/Bitops3BitBitsInByte.sts | 46 + test/parser/sts/BitopsBitsInByte-expected.txt | 1905 ++++ test/parser/sts/BitopsBitsInByte.sts | 49 + test/parser/sts/BitopsBitwiseAnd-expected.txt | 1059 ++ test/parser/sts/BitopsBitwiseAnd.sts | 34 + test/parser/sts/BitopsNSieveBits-expected.txt | 3303 ++++++ test/parser/sts/BitopsNSieveBits.sts | 61 + .../sts/ControlFlowRecursive-expected.txt | 3243 ++++++ test/parser/sts/ControlFlowRecursive.sts | 61 + test/parser/sts/MathCordic-expected.txt | 1 + test/parser/sts/MathCordic.sts | 91 + test/parser/sts/MathPartialSums-expected.txt | 4860 +++++++++ test/parser/sts/MathPartialSums.sts | 90 + test/parser/sts/MathSpectralNorm-expected.txt | 5640 ++++++++++ test/parser/sts/MathSpectralNorm.sts | 94 + test/parser/sts/Morph3d-expected.txt | 3393 ++++++ test/parser/sts/Morph3d.sts | 62 + test/parser/sts/StringBase64-expected.txt | 1 + test/parser/sts/StringBase64.sts | 124 + test/parser/sts/StringFasta-expected.txt | 9681 +++++++++++++++++ test/parser/sts/StringFasta.sts | 145 + test/parser/sts/anonymous_class-expected.txt | 566 + test/parser/sts/anonymous_class.sts | 21 + test/parser/sts/array-expected.txt | 657 ++ test/parser/sts/array.sts | 23 + test/parser/sts/array_type-expected.txt | 942 ++ test/parser/sts/array_type.sts | 28 + test/parser/sts/assert-expected.txt | 839 ++ test/parser/sts/assert.sts | 26 + test/parser/sts/assign-expected.txt | 324 + test/parser/sts/assign.sts | 21 + test/parser/sts/assign_bad-expected.txt | 1 + test/parser/sts/assign_bad.sts | 21 + test/parser/sts/assignments-expected.txt | 1408 +++ test/parser/sts/assignments.sts | 39 + test/parser/sts/binary_op-expected.txt | 2055 ++++ test/parser/sts/binary_op.sts | 42 + .../parser/sts/binary_operations-expected.txt | 2911 +++++ test/parser/sts/binary_operations.sts | 44 + test/parser/sts/blocks-expected.txt | 1 + test/parser/sts/blocks.sts | 24 + test/parser/sts/blocks_scopes-expected.txt | 1 + test/parser/sts/blocks_scopes.sts | 26 + test/parser/sts/boolean-expected.txt | 172 + test/parser/sts/boolean.sts | 17 + test/parser/sts/boolean_cond-expected.txt | 279 + test/parser/sts/boolean_cond.sts | 23 + test/parser/sts/break-expected.txt | 1 + test/parser/sts/break.sts | 21 + .../calling_superclass_methods-expected.txt | 1 + .../parser/sts/calling_superclass_methods.sts | 26 + test/parser/sts/calls-expected.txt | 671 ++ test/parser/sts/calls.sts | 27 + test/parser/sts/cast_expressions-expected.txt | 343 + test/parser/sts/cast_expressions.sts | 20 + test/parser/sts/class_init-expected.txt | 401 + test/parser/sts/class_init.sts | 22 + test/parser/sts/class_instance-expected.txt | 467 + test/parser/sts/class_instance.sts | 21 + .../sts/class_instance_creation-expected.txt | 1073 ++ test/parser/sts/class_instance_creation.sts | 32 + .../class_instance_initializer-expected.txt | 2576 +++++ .../parser/sts/class_instance_initializer.sts | 68 + .../sts/class_property_access-expected.txt | 722 ++ test/parser/sts/class_property_access.sts | 26 + .../sts/class_static_initializer-expected.txt | 756 ++ test/parser/sts/class_static_initializer.sts | 29 + test/parser/sts/classes-expected.txt | 646 ++ test/parser/sts/classes.sts | 26 + test/parser/sts/comment_block-expected.txt | 58 + test/parser/sts/comment_block.sts | 34 + test/parser/sts/comment_line-expected.txt | 58 + test/parser/sts/comment_line.sts | 16 + test/parser/sts/const-expected.txt | 200 + test/parser/sts/const.sts | 17 + test/parser/sts/const_enum-expected.txt | 1 + test/parser/sts/const_enum.sts | 16 + test/parser/sts/constructor_test-expected.txt | 1141 ++ test/parser/sts/constructor_test.sts | 41 + test/parser/sts/constructors-expected.txt | 1175 ++ test/parser/sts/constructors.sts | 35 + test/parser/sts/continue-expected.txt | 1 + test/parser/sts/continue.sts | 21 + test/parser/sts/decl_infer-expected.txt | 559 + test/parser/sts/decl_infer.sts | 26 + test/parser/sts/defer-plus-expected.txt | 919 ++ test/parser/sts/defer-plus.sts | 32 + test/parser/sts/empty_class-expected.txt | 335 + test/parser/sts/empty_class.sts | 20 + test/parser/sts/empty_statement-expected.txt | 924 ++ test/parser/sts/empty_statement.sts | 34 + test/parser/sts/enum-expected.txt | 336 + test/parser/sts/enum.sts | 18 + .../sts/enum_with_class_behavior-expected.txt | 790 ++ test/parser/sts/enum_with_class_behavior.sts | 37 + test/parser/sts/exports-expected.txt | 698 ++ test/parser/sts/exports.sts | 22 + test/parser/sts/field_decl-expected.txt | 843 ++ test/parser/sts/field_decl.sts | 29 + test/parser/sts/fields-expected.txt | 1 + test/parser/sts/fields.sts | 28 + .../parser/sts/final_empty_class-expected.txt | 335 + test/parser/sts/final_empty_class.sts | 20 + test/parser/sts/for_of-expected.txt | 1 + test/parser/sts/for_of.sts | 29 + test/parser/sts/for_with_break-expected.txt | 639 ++ test/parser/sts/for_with_break.sts | 26 + test/parser/sts/function-expected.txt | 1 + test/parser/sts/function.sts | 36 + test/parser/sts/function_decl-expected.txt | 277 + test/parser/sts/function_decl.sts | 16 + test/parser/sts/generic_function-expected.txt | 1 + test/parser/sts/generic_function.sts | 24 + test/parser/sts/generics_1-expected.txt | 1222 +++ test/parser/sts/generics_1.sts | 32 + test/parser/sts/identifier-expected.txt | 248 + test/parser/sts/identifier.sts | 20 + test/parser/sts/if-expected.txt | 2827 +++++ test/parser/sts/if.sts | 73 + test/parser/sts/ifs-expected.txt | 480 + test/parser/sts/ifs.sts | 26 + .../parser/sts/index_expressions-expected.txt | 407 + test/parser/sts/index_expressions.sts | 21 + test/parser/sts/inheritance-expected.txt | 1293 +++ test/parser/sts/inheritance.sts | 38 + test/parser/sts/instanceof-expected.txt | 365 + test/parser/sts/instanceof.sts | 22 + test/parser/sts/interface-expected.txt | 282 + test/parser/sts/interface.sts | 18 + test/parser/sts/interfaces-expected.txt | 670 ++ test/parser/sts/interfaces.sts | 27 + test/parser/sts/labeled-expected.txt | 882 ++ test/parser/sts/labeled.sts | 27 + test/parser/sts/lexer001-expected.txt | 1 + test/parser/sts/lexer001.sts | 16 + test/parser/sts/lexer002-expected.txt | 1 + test/parser/sts/lexer002.sts | 17 + test/parser/sts/literals-expected.txt | 1053 ++ test/parser/sts/literals.sts | 34 + .../sts/localClassIsPermitted-expected.txt | 1 + test/parser/sts/localClassIsPermitted.sts | 22 + test/parser/sts/loops-expected.txt | 2414 ++++ test/parser/sts/loops.sts | 65 + test/parser/sts/method_empty-expected.txt | 714 ++ test/parser/sts/method_empty.sts | 26 + test/parser/sts/method_full-expected.txt | 1431 +++ test/parser/sts/method_full.sts | 34 + test/parser/sts/methods-expected.txt | 1966 ++++ test/parser/sts/methods.sts | 41 + test/parser/sts/named_types-expected.txt | 1338 +++ test/parser/sts/named_types.sts | 34 + test/parser/sts/new_expressions-expected.txt | 403 + test/parser/sts/new_expressions.sts | 26 + test/parser/sts/null-expected.txt | 2304 ++++ test/parser/sts/null.sts | 48 + test/parser/sts/null_invalid-expected.txt | 109 + test/parser/sts/null_invalid.sts | 16 + test/parser/sts/object-expected.txt | 136 + test/parser/sts/object.sts | 16 + test/parser/sts/override_method-expected.txt | 642 ++ test/parser/sts/override_method.sts | 26 + test/parser/sts/panic-if-expected.txt | 1 + test/parser/sts/panic-if.sts | 20 + test/parser/sts/panic-statement-expected.txt | 317 + test/parser/sts/panic-statement.sts | 22 + .../parentheses_expression_value-expected.txt | 614 ++ .../sts/parentheses_expression_value.sts | 25 + ...redefined_non_primitive_types-expected.txt | 1 + .../sts/predefined_non_primitive_types.sts | 37 + test/parser/sts/predefined_types-expected.txt | 402 + test/parser/sts/predefined_types.sts | 26 + ...egression-target-type-context-expected.txt | 2030 ++++ .../sts/regression-target-type-context.sts | 42 + test/parser/sts/return-expected.txt | 1 + test/parser/sts/return.sts | 21 + test/parser/sts/scoped_decl-expected.txt | 356 + test/parser/sts/scoped_decl.sts | 21 + test/parser/sts/simple_types-expected.txt | 706 ++ test/parser/sts/simple_types.sts | 29 + .../sts/special_signatures-expected.txt | 1 + test/parser/sts/special_signatures.sts | 19 + test/parser/sts/string-expected.txt | 150 + test/parser/sts/string.sts | 16 + test/parser/sts/switch-expected.txt | 680 ++ test/parser/sts/switch.sts | 31 + test/parser/sts/switch2-expected.txt | 652 ++ test/parser/sts/switch2.sts | 31 + test/parser/sts/ternary-expected.txt | 282 + test/parser/sts/ternary.sts | 19 + test/parser/sts/test_enum-expected.txt | 1136 ++ test/parser/sts/test_enum.sts | 55 + test/parser/sts/test_interface-expected.txt | 1234 +++ test/parser/sts/test_interface.sts | 29 + .../sts/topLevelStaticClass-expected.txt | 1 + test/parser/sts/topLevelStaticClass.sts | 18 + test/parser/sts/trap-expected.txt | 1 + .../sts/trap-missing-catch-expected.txt | 1 + test/parser/sts/trap-missing-catch.sts | 21 + test/parser/sts/trap.sts | 25 + test/parser/sts/type_cast-expected.txt | 793 ++ test/parser/sts/type_cast.sts | 26 + test/parser/sts/type_references-expected.txt | 1 + test/parser/sts/type_references.sts | 19 + test/parser/sts/types_decls-expected.txt | 1 + test/parser/sts/types_decls.sts | 57 + test/parser/sts/unary_op-expected.txt | 554 + test/parser/sts/unary_op.sts | 23 + test/parser/sts/unary_operations-expected.txt | 1093 ++ test/parser/sts/unary_operations.sts | 30 + test/parser/sts/var_declare-expected.txt | 883 ++ test/parser/sts/var_declare.sts | 28 + test/parser/sts/void-expected.txt | 181 + test/parser/sts/void.sts | 18 + .../ts/test-class-constructor-expected.txt | 1 - .../ts/test-class-constructor4-expected.txt | 1 - .../ts/test-class-definition-expected.txt | 14 +- .../ts/test-class-definiton18-expected.txt | 5 +- .../ts/test-class-definiton7-expected.txt | 5 +- .../test-class-method-overload-expected.txt | 6 +- .../test-class-method-overload1-expected.txt | 5 +- .../test-class-method-overload10-expected.txt | 5 +- .../test-class-method-overload11-expected.txt | 5 +- .../test-class-method-overload12-expected.txt | 5 +- .../test-class-method-overload13-expected.txt | 5 +- .../test-class-method-overload2-expected.txt | 5 +- .../test-class-method-overload3-expected.txt | 5 +- .../test-class-method-overload4-expected.txt | 5 +- .../test-class-method-overload5-expected.txt | 5 +- .../test-class-method-overload6-expected.txt | 5 +- .../test-class-method-overload7-expected.txt | 5 +- .../test-class-method-overload8-expected.txt | 5 +- .../test-class-method-overload9-expected.txt | 5 +- test/parser/ts/test-func-param6-expected.txt | 2 +- test/parser/ts/test-interface1-expected.txt | 59 +- test/parser/ts/test-interface2-expected.txt | 2 +- .../ts/test-keyword-declare-expected.txt | 5 +- .../ts/test-ts-mapped-type1-expected.txt | 2 +- .../ts/test-ts-mapped-type2-expected.txt | 2 +- .../ts/test-ts-mapped-type3-expected.txt | 2 +- .../test-ts-parameter-property-expected.txt | 4 - .../parser/ts/test-type-literal1-expected.txt | 2 +- test/parser/ts/test_decorator-expected.txt | 1 - test/parser/ts/test_decorator3-expected.txt | 5 +- test/parser/ts/test_decorator6-expected.txt | 2 +- test/parser/ts/test_generic-expected.txt | 75 +- test/parser/ts/test_generic.ts | 6 +- test/parser/ts/test_this_type-expected.txt | 5 +- test/runner.py | 1124 ++ test/runtime/sts/AccessBinaryTrees.sts | 82 + test/runtime/sts/AccessFannkuch.sts | 93 + test/runtime/sts/AccessNSieve.sts | 63 + test/runtime/sts/Bitops3BitBitsInByte.sts | 44 + test/runtime/sts/BitopsBitsInByte.sts | 49 + test/runtime/sts/BitopsBitwiseAnd.sts | 35 + test/runtime/sts/BitopsNSieveBits.sts | 63 + test/runtime/sts/ClassNewInstance.sts | 36 + test/runtime/sts/ControlFlowRecursive.sts | 61 + test/runtime/sts/MathPartialSums.sts | 88 + test/runtime/sts/MathSpectralNorm.sts | 94 + test/runtime/sts/Morph3d.sts | 63 + test/runtime/sts/cast.sts | 103 + test/runtime/sts/char-type.sts | 52 + test/runtime/sts/class-init.sts | 50 + test/runtime/sts/count.sts | 21 + test/runtime/sts/generics_1.sts | 41 + test/runtime/sts/skippedTest.sts | 17 + test/stsskiplist.txt | 1 + util/helpers.cpp | 89 +- util/helpers.h | 16 +- util/ustring.cpp | 1 + util/ustring.h | 19 +- 968 files changed, 168457 insertions(+), 10338 deletions(-) create mode 100644 binder/ASBinder.cpp create mode 100644 binder/ASBinder.h create mode 100644 binder/JSBinder.cpp create mode 100644 binder/JSBinder.h create mode 100644 binder/STSBinder.cpp create mode 100644 binder/STSBinder.h create mode 100644 binder/TSBinder.cpp create mode 100644 binder/TSBinder.h create mode 100644 binder/TypedBinder.cpp create mode 100644 binder/TypedBinder.h create mode 100644 binder/recordTable.cpp create mode 100644 binder/recordTable.h create mode 100644 checker/ASchecker.cpp create mode 100644 checker/ASchecker.h create mode 100644 checker/JSchecker.cpp create mode 100644 checker/JSchecker.h create mode 100644 checker/STSchecker.cpp create mode 100644 checker/STSchecker.h create mode 100644 checker/TSchecker.cpp rename typescript/checker.h => checker/TSchecker.h (51%) rename typescript/core/typeRelation.cpp => checker/checker.cpp (57%) create mode 100644 checker/checker.h rename {typescript/core => checker}/checkerContext.cpp (100%) rename {typescript/core => checker}/checkerContext.h (57%) create mode 100644 checker/sts/aliveAnalyzer.cpp create mode 100644 checker/sts/aliveAnalyzer.h create mode 100644 checker/sts/arithmetic.cpp create mode 100644 checker/sts/arithmetic.h create mode 100644 checker/sts/baseAnalyzer.cpp create mode 100644 checker/sts/baseAnalyzer.h create mode 100644 checker/sts/boxingConverter.cpp create mode 100644 checker/sts/boxingConverter.h create mode 100644 checker/sts/function.cpp create mode 100644 checker/sts/helpers.cpp create mode 100644 checker/sts/narrowingConverter.cpp create mode 100644 checker/sts/narrowingConverter.h create mode 100644 checker/sts/narrowingWideningConverter.cpp create mode 100644 checker/sts/narrowingWideningConverter.h create mode 100644 checker/sts/object.cpp create mode 100644 checker/sts/primitiveWrappers.cpp create mode 100644 checker/sts/primitiveWrappers.h create mode 100644 checker/sts/typeConverter.cpp create mode 100644 checker/sts/typeConverter.h create mode 100644 checker/sts/typeCreation.cpp create mode 100644 checker/sts/typeRelationContext.cpp create mode 100644 checker/sts/typeRelationContext.h create mode 100644 checker/sts/unboxingConverter.cpp create mode 100644 checker/sts/unboxingConverter.h create mode 100644 checker/sts/wideningConverter.cpp create mode 100644 checker/sts/wideningConverter.h rename {typescript/core => checker/ts}/binaryLikeExpression.cpp (85%) rename {typescript/core => checker/ts}/destructuringContext.cpp (95%) rename {typescript/core => checker/ts}/destructuringContext.h (64%) rename {typescript/core => checker/ts}/function.cpp (76%) rename {typescript/core => checker/ts}/helpers.cpp (73%) rename {typescript/core => checker/ts}/object.cpp (78%) rename {typescript/core => checker/ts}/typeCreation.cpp (50%) rename {typescript/core => checker/ts}/typeElaborationContext.cpp (94%) rename {typescript/core => checker/ts}/typeElaborationContext.h (76%) rename {typescript/core => checker/ts}/util.cpp (76%) rename {typescript => checker}/types/globalTypesHolder.cpp (56%) rename {typescript => checker}/types/globalTypesHolder.h (64%) rename {typescript => checker}/types/signature.cpp (81%) rename {typescript => checker}/types/signature.h (59%) create mode 100644 checker/types/sts/byteType.cpp create mode 100644 checker/types/sts/byteType.h create mode 100644 checker/types/sts/charType.cpp create mode 100644 checker/types/sts/charType.h create mode 100644 checker/types/sts/doubleType.cpp create mode 100644 checker/types/sts/doubleType.h create mode 100644 checker/types/sts/floatType.cpp create mode 100644 checker/types/sts/floatType.h create mode 100644 checker/types/sts/intType.cpp create mode 100644 checker/types/sts/intType.h create mode 100644 checker/types/sts/longType.cpp create mode 100644 checker/types/sts/longType.h create mode 100644 checker/types/sts/shortType.cpp create mode 100644 checker/types/sts/shortType.h create mode 100644 checker/types/sts/stsArrayType.cpp create mode 100644 checker/types/sts/stsArrayType.h create mode 100644 checker/types/sts/stsBooleanType.cpp create mode 100644 checker/types/sts/stsBooleanType.h create mode 100644 checker/types/sts/stsFunctionType.cpp create mode 100644 checker/types/sts/stsFunctionType.h create mode 100644 checker/types/sts/stsObjectType.cpp create mode 100644 checker/types/sts/stsObjectType.h create mode 100644 checker/types/sts/stsStringType.cpp create mode 100644 checker/types/sts/stsStringType.h create mode 100644 checker/types/sts/stsTypeParameter.cpp create mode 100644 checker/types/sts/stsTypeParameter.h create mode 100644 checker/types/sts/stsTypeReference.cpp create mode 100644 checker/types/sts/stsTypeReference.h create mode 100644 checker/types/sts/stsVoidType.cpp rename lexer/templates/keywordsMap.h.erb => checker/types/sts/stsVoidType.h (42%) create mode 100644 checker/types/sts/types.h create mode 100644 checker/types/sts/wildcardType.cpp create mode 100644 checker/types/sts/wildcardType.h rename {typescript/types => checker/types/ts}/anyType.cpp (100%) rename {typescript/types => checker/types/ts}/anyType.h (87%) rename {typescript/types => checker/types/ts}/arrayType.cpp (96%) rename {typescript/types => checker/types/ts}/arrayType.h (89%) rename {typescript/types => checker/types/ts}/bigintLiteralType.cpp (100%) rename {typescript/types => checker/types/ts}/bigintLiteralType.h (89%) rename {typescript/types => checker/types/ts}/bigintType.cpp (100%) rename {typescript/types => checker/types/ts}/bigintType.h (87%) rename {typescript/types => checker/types/ts}/booleanLiteralType.cpp (100%) rename {typescript/types => checker/types/ts}/booleanLiteralType.h (88%) rename {typescript/types => checker/types/ts}/booleanType.cpp (100%) rename {typescript/types => checker/types/ts}/booleanType.h (87%) rename {typescript/types => checker/types/ts}/constructorType.cpp (95%) rename {typescript/types => checker/types/ts}/constructorType.h (90%) rename {typescript/types => checker/types/ts}/elementFlags.h (90%) rename {typescript/types => checker/types/ts}/enumLiteralType.cpp (96%) rename {typescript/types => checker/types/ts}/enumLiteralType.h (90%) rename {typescript/types => checker/types/ts}/enumType.cpp (100%) rename {typescript/types => checker/types/ts}/enumType.h (90%) rename {typescript/types => checker/types/ts}/functionType.cpp (96%) rename {typescript/types => checker/types/ts}/functionType.h (90%) rename {typescript/types => checker/types/ts}/indexInfo.cpp (100%) rename {typescript/types => checker/types/ts}/indexInfo.h (92%) rename {typescript/types => checker/types/ts}/interfaceType.cpp (98%) rename {typescript/types => checker/types/ts}/interfaceType.h (97%) rename {typescript/types => checker/types/ts}/neverType.cpp (100%) rename {typescript/types => checker/types/ts}/neverType.h (87%) rename {typescript/types => checker/types/ts}/nonPrimitiveType.cpp (100%) rename {typescript/types => checker/types/ts}/nonPrimitiveType.h (86%) rename {typescript/types => checker/types/ts}/nullType.cpp (100%) rename {typescript/types => checker/types/ts}/nullType.h (88%) rename {typescript/types => checker/types/ts}/numberLiteralType.cpp (96%) rename {typescript/types => checker/types/ts}/numberLiteralType.h (88%) rename {typescript/types => checker/types/ts}/numberType.cpp (96%) rename {typescript/types => checker/types/ts}/numberType.h (87%) rename {typescript/types => checker/types/ts}/objectDescriptor.cpp (93%) rename {typescript/types => checker/types/ts}/objectDescriptor.h (93%) rename {typescript/types => checker/types/ts}/objectLiteralType.cpp (94%) rename {typescript/types => checker/types/ts}/objectLiteralType.h (90%) rename {typescript/types => checker/types/ts}/objectType.cpp (97%) rename {typescript/types => checker/types/ts}/objectType.h (96%) rename {typescript/types => checker/types/ts}/stringLiteralType.cpp (100%) rename {typescript/types => checker/types/ts}/stringLiteralType.h (88%) rename {typescript/types => checker/types/ts}/stringType.cpp (100%) rename {typescript/types => checker/types/ts}/stringType.h (87%) rename {typescript/types => checker/types/ts}/tupleType.cpp (97%) rename {typescript/types => checker/types/ts}/tupleType.h (92%) rename {typescript/types => checker/types/ts}/typeParameter.cpp (100%) rename {typescript/types => checker/types/ts}/typeParameter.h (90%) rename {typescript/types => checker/types/ts}/typeReference.cpp (100%) rename {typescript/types => checker/types/ts}/typeReference.h (84%) rename {typescript/types => checker/types/ts}/types.h (89%) rename {typescript/types => checker/types/ts}/undefinedType.cpp (100%) rename {typescript/types => checker/types/ts}/undefinedType.h (87%) rename {typescript/types => checker/types/ts}/unionType.cpp (98%) rename {typescript/types => checker/types/ts}/unionType.h (96%) rename {typescript/types => checker/types/ts}/unknownType.cpp (100%) rename {typescript/types => checker/types/ts}/unknownType.h (87%) rename {typescript/types => checker/types/ts}/voidType.cpp (100%) rename {typescript/types => checker/types/ts}/voidType.h (87%) rename {typescript => checker}/types/type.cpp (63%) rename {typescript => checker}/types/type.h (69%) rename {typescript => checker}/types/typeFacts.h (98%) create mode 100644 checker/types/typeFlag.h create mode 100644 checker/types/typeMapping.h rename {typescript => checker}/types/typeRelation.cpp (84%) rename {typescript => checker}/types/typeRelation.h (50%) create mode 100644 compiler/core/JSemitter.cpp create mode 100644 compiler/core/JSemitter.h create mode 100644 compiler/core/STSGen.cpp create mode 100644 compiler/core/STSGen.h create mode 100644 compiler/core/STSemitter.cpp create mode 100644 compiler/core/STSemitter.h create mode 100644 compiler/core/STSfunction.cpp create mode 100644 compiler/core/STSfunction.h create mode 100644 compiler/core/codeGen.cpp create mode 100644 compiler/core/codeGen.h create mode 100644 compiler/core/compileJob.cpp create mode 100644 compiler/core/compileJob.h rename compiler/core/{inlineCache.h => programElement.cpp} (71%) create mode 100644 compiler/core/programElement.h create mode 100644 compiler/core/regSpiller.cpp create mode 100644 compiler/core/regSpiller.h rename compiler/core/{inlineCache.cpp => targetTypeContext.cpp} (62%) create mode 100644 compiler/core/targetTypeContext.h create mode 100644 compiler/core/vReg.cpp create mode 100644 compiler/core/vReg.h create mode 100644 compiler/scripts/signatures.rb create mode 100644 compiler/scripts/signatures.yaml create mode 100644 compiler/templates/signatures.h.erb create mode 100644 ir/astNode.cpp rename ir/{ts => base}/tsIndexSignature.cpp (87%) rename ir/{ts => base}/tsIndexSignature.h (66%) rename ir/{ts => base}/tsMethodSignature.cpp (86%) rename ir/{ts => base}/tsMethodSignature.h (76%) rename ir/{ts => base}/tsPropertySignature.cpp (87%) rename ir/{ts => base}/tsPropertySignature.h (64%) rename ir/{ts => base}/tsSignatureDeclaration.cpp (89%) rename ir/{ts => base}/tsSignatureDeclaration.h (74%) create mode 100644 ir/expressions/literals/charLiteral.cpp create mode 100644 ir/expressions/literals/charLiteral.h create mode 100644 ir/statements/assertStatement.cpp create mode 100644 ir/statements/assertStatement.h create mode 100644 ir/statements/deferStatement.cpp create mode 100644 ir/statements/deferStatement.h create mode 100644 ir/statements/panicStatement.cpp create mode 100644 ir/statements/panicStatement.h create mode 100644 ir/statements/trapStatement.cpp create mode 100644 ir/statements/trapStatement.h create mode 100644 ir/sts/stsClassLiteral.cpp create mode 100644 ir/sts/stsClassLiteral.h create mode 100644 ir/sts/stsNewArrayInstanceExpression.cpp create mode 100644 ir/sts/stsNewArrayInstanceExpression.h create mode 100644 ir/sts/stsNewClassInstanceExpression.cpp create mode 100644 ir/sts/stsNewClassInstanceExpression.h create mode 100644 ir/sts/stsNewMultiDimArrayInstanceExpression.cpp create mode 100644 ir/sts/stsNewMultiDimArrayInstanceExpression.h create mode 100644 ir/sts/stsPackageDeclaration.cpp create mode 100644 ir/sts/stsPackageDeclaration.h create mode 100644 ir/sts/stsPrimitiveType.cpp create mode 100644 ir/sts/stsPrimitiveType.h create mode 100644 ir/sts/stsScript.cpp create mode 100644 ir/sts/stsScript.h create mode 100644 ir/sts/stsTryExpression.cpp create mode 100644 ir/sts/stsTryExpression.h create mode 100644 ir/sts/stsTypeReference.cpp create mode 100644 ir/sts/stsTypeReference.h create mode 100644 ir/sts/stsTypeReferencePart.cpp create mode 100644 ir/sts/stsTypeReferencePart.h create mode 100644 ir/sts/stsWildcardType.cpp create mode 100644 ir/sts/stsWildcardType.h create mode 100644 lexer/ASLexer.cpp create mode 100644 lexer/ASLexer.h create mode 100644 lexer/STSLexer.cpp create mode 100644 lexer/STSLexer.h create mode 100644 lexer/TSLexer.cpp create mode 100644 lexer/TSLexer.h create mode 100644 lexer/keywords.cpp create mode 100644 lexer/keywordsBase.h create mode 100644 lexer/scripts/keywords.yaml create mode 100644 lexer/token/number.cpp create mode 100644 lexer/token/number.h create mode 100644 parser/ASparser.cpp create mode 100644 parser/ASparser.h create mode 100644 parser/JSparser.cpp create mode 100644 parser/JSparser.h create mode 100644 parser/STSparser.cpp create mode 100644 parser/STSparser.h create mode 100644 parser/TSparser.cpp create mode 100644 parser/TSparser.h create mode 100644 parser/TypedParser.cpp create mode 100644 parser/TypedParser.h create mode 100644 stdlib/ets/io/PrintStream.sts create mode 100644 stdlib/ets/io/Serializable.sts create mode 100644 stdlib/ets/lang/AbstractStringBuilder.sts create mode 100644 stdlib/ets/lang/AssertionError.sts create mode 100644 stdlib/ets/lang/Boolean.sts create mode 100644 stdlib/ets/lang/Char.sts create mode 100644 stdlib/ets/lang/Class.sts create mode 100644 stdlib/ets/lang/Double.sts create mode 100644 stdlib/ets/lang/Error.sts create mode 100644 stdlib/ets/lang/Exception.sts create mode 100644 stdlib/ets/lang/Float.sts create mode 100644 stdlib/ets/lang/Integer.sts create mode 100644 stdlib/ets/lang/Long.sts create mode 100644 stdlib/ets/lang/Math.sts create mode 100644 stdlib/ets/lang/NullPointerException.sts create mode 100644 stdlib/ets/lang/Object.sts create mode 100644 stdlib/ets/lang/RuntimeException.sts create mode 100644 stdlib/ets/lang/Short.sts create mode 100644 stdlib/ets/lang/String.sts create mode 100644 stdlib/ets/lang/StringBuilder.sts create mode 100644 stdlib/ets/lang/System.sts create mode 100644 stdlib/ets/lang/Throwable.sts create mode 100644 test/compiler/sts/abstractMethodDeclaredInParentClass-expected.txt create mode 100644 test/compiler/sts/abstractMethodDeclaredInParentClass.sts create mode 100644 test/compiler/sts/abstractNewClassInstanceExpression-expected.txt create mode 100644 test/compiler/sts/abstractNewClassInstanceExpression.sts create mode 100644 test/compiler/sts/interfaceMethodNotOverridden-expected.txt create mode 100644 test/compiler/sts/interfaceMethodNotOverridden.sts create mode 100644 test/compiler/sts/invalidPrivateAcces-expected.txt create mode 100644 test/compiler/sts/invalidPrivateAccess1-expected.txt create mode 100644 test/compiler/sts/invalidPrivateAccess1.sts create mode 100644 test/compiler/sts/invalidPrivateAccess2-expected.txt create mode 100644 test/compiler/sts/invalidPrivateAccess2.sts create mode 100644 test/compiler/sts/invalidPrivateAccess3-expected.txt create mode 100644 test/compiler/sts/invalidPrivateAccess3.sts create mode 100644 test/compiler/sts/invalidPrivateAccess4-expected.txt create mode 100644 test/compiler/sts/invalidPrivateAccess4.sts create mode 100644 test/compiler/sts/invalidPrivateAccess5-expected.txt create mode 100644 test/compiler/sts/invalidPrivateAccess5.sts create mode 100644 test/compiler/sts/invalidPrivateAccess6-expected.txt create mode 100644 test/compiler/sts/invalidPrivateAccess6.sts create mode 100644 test/compiler/sts/methodOverrideCovariantReturnType-expected.txt create mode 100644 test/compiler/sts/methodOverrideCovariantReturnType.sts create mode 100644 test/compiler/sts/methodOverrideDifferentSignature-expected.txt create mode 100644 test/compiler/sts/methodOverrideDifferentSignature.sts create mode 100644 test/compiler/sts/methodOverrideWithoutModifier-expected.txt create mode 100644 test/compiler/sts/methodOverrideWithoutModifier.sts create mode 100644 test/compiler/sts/multipleMethodOverride-expected.txt create mode 100644 test/compiler/sts/multipleMethodOverride.sts create mode 100644 test/compiler/sts/overrideModifierNotOverriding-expected.txt create mode 100644 test/compiler/sts/overrideModifierNotOverriding.sts create mode 100644 test/compiler/sts/privateMethodOverride-expected.txt create mode 100644 test/compiler/sts/privateMethodOverride.sts create mode 100644 test/compiler/sts/staticInitializerInInnerClass-expected.txt create mode 100644 test/compiler/sts/staticInitializerInInnerClass.sts create mode 100644 test/compiler/sts/superReferenceFromStaticContext-expected.txt create mode 100644 test/compiler/sts/superReferenceFromStaticContext.sts create mode 100644 test/compiler/sts/thisReferenceFromStaticContext-expected.txt create mode 100644 test/compiler/sts/thisReferenceFromStaticContext.sts create mode 100644 test/compiler/sts/typeVarReferenceFromStaticContext-expected.txt create mode 100644 test/compiler/sts/typeVarReferenceFromStaticContext.sts create mode 100644 test/parser/js/module-test-export-all-expected.txt rename test/parser/js/{test-export-all.js => module-test-export-all.js} (100%) create mode 100644 test/parser/js/module-test-export-named-decl-expected.txt rename test/parser/js/{test-export-named-decl.js => module-test-export-named-decl.js} (100%) create mode 100644 test/parser/js/module-test-import-decl-expected.txt rename test/parser/js/{test-import-decl.js => module-test-import-decl.js} (100%) create mode 100644 test/parser/js/module-test-import-expression-expected.txt rename test/parser/js/{test-import-expression.js => module-test-import-expression.js} (100%) create mode 100644 test/parser/js/module-test-import-meta-expected.txt rename test/parser/js/{test-import-meta.js => module-test-import-meta.js} (100%) create mode 100644 test/parser/js/module-test-imported-decl1-expected.txt rename test/parser/js/{test-imported-decl1.js => module-test-imported-decl1.js} (100%) create mode 100644 test/parser/js/module-test-one-default-export-allowed-expected.txt rename test/parser/js/{test-one-default-export-allowed.js => module-test-one-default-export-allowed.js} (100%) delete mode 100644 test/parser/js/test-export-all-expected.txt delete mode 100644 test/parser/js/test-export-named-decl-expected.txt rename test/parser/js/{test-function-decl-expected.txt => test-function-decl-1-expected.txt} (90%) rename test/parser/js/{test-function-decl.js => test-function-decl-1.js} (96%) create mode 100644 test/parser/js/test-function-decl-2-expected.txt create mode 100644 test/parser/js/test-function-decl-2.js delete mode 100644 test/parser/js/test-import-decl-expected.txt delete mode 100644 test/parser/js/test-import-expression-expected.txt delete mode 100644 test/parser/js/test-import-meta-expected.txt delete mode 100644 test/parser/js/test-imported-decl1-expected.txt delete mode 100644 test/parser/js/test-one-default-export-allowed-expected.txt create mode 100644 test/parser/sts/AccessBinaryTrees-expected.txt create mode 100644 test/parser/sts/AccessBinaryTrees.sts create mode 100644 test/parser/sts/AccessFannkuch-expected.txt create mode 100644 test/parser/sts/AccessFannkuch.sts create mode 100644 test/parser/sts/AccessNBody-expected.txt create mode 100644 test/parser/sts/AccessNBody.sts create mode 100644 test/parser/sts/AccessNSieve-expected.txt create mode 100644 test/parser/sts/AccessNSieve.sts create mode 100644 test/parser/sts/Bitops3BitBitsInByte-expected.txt create mode 100644 test/parser/sts/Bitops3BitBitsInByte.sts create mode 100644 test/parser/sts/BitopsBitsInByte-expected.txt create mode 100644 test/parser/sts/BitopsBitsInByte.sts create mode 100644 test/parser/sts/BitopsBitwiseAnd-expected.txt create mode 100644 test/parser/sts/BitopsBitwiseAnd.sts create mode 100644 test/parser/sts/BitopsNSieveBits-expected.txt create mode 100644 test/parser/sts/BitopsNSieveBits.sts create mode 100644 test/parser/sts/ControlFlowRecursive-expected.txt create mode 100644 test/parser/sts/ControlFlowRecursive.sts create mode 100644 test/parser/sts/MathCordic-expected.txt create mode 100644 test/parser/sts/MathCordic.sts create mode 100644 test/parser/sts/MathPartialSums-expected.txt create mode 100644 test/parser/sts/MathPartialSums.sts create mode 100644 test/parser/sts/MathSpectralNorm-expected.txt create mode 100644 test/parser/sts/MathSpectralNorm.sts create mode 100644 test/parser/sts/Morph3d-expected.txt create mode 100644 test/parser/sts/Morph3d.sts create mode 100644 test/parser/sts/StringBase64-expected.txt create mode 100644 test/parser/sts/StringBase64.sts create mode 100644 test/parser/sts/StringFasta-expected.txt create mode 100644 test/parser/sts/StringFasta.sts create mode 100644 test/parser/sts/anonymous_class-expected.txt create mode 100644 test/parser/sts/anonymous_class.sts create mode 100644 test/parser/sts/array-expected.txt create mode 100644 test/parser/sts/array.sts create mode 100644 test/parser/sts/array_type-expected.txt create mode 100644 test/parser/sts/array_type.sts create mode 100644 test/parser/sts/assert-expected.txt create mode 100644 test/parser/sts/assert.sts create mode 100644 test/parser/sts/assign-expected.txt create mode 100644 test/parser/sts/assign.sts create mode 100644 test/parser/sts/assign_bad-expected.txt create mode 100644 test/parser/sts/assign_bad.sts create mode 100644 test/parser/sts/assignments-expected.txt create mode 100644 test/parser/sts/assignments.sts create mode 100644 test/parser/sts/binary_op-expected.txt create mode 100644 test/parser/sts/binary_op.sts create mode 100644 test/parser/sts/binary_operations-expected.txt create mode 100644 test/parser/sts/binary_operations.sts create mode 100644 test/parser/sts/blocks-expected.txt create mode 100644 test/parser/sts/blocks.sts create mode 100644 test/parser/sts/blocks_scopes-expected.txt create mode 100644 test/parser/sts/blocks_scopes.sts create mode 100644 test/parser/sts/boolean-expected.txt create mode 100644 test/parser/sts/boolean.sts create mode 100644 test/parser/sts/boolean_cond-expected.txt create mode 100644 test/parser/sts/boolean_cond.sts create mode 100644 test/parser/sts/break-expected.txt create mode 100644 test/parser/sts/break.sts create mode 100644 test/parser/sts/calling_superclass_methods-expected.txt create mode 100644 test/parser/sts/calling_superclass_methods.sts create mode 100644 test/parser/sts/calls-expected.txt create mode 100644 test/parser/sts/calls.sts create mode 100644 test/parser/sts/cast_expressions-expected.txt create mode 100644 test/parser/sts/cast_expressions.sts create mode 100644 test/parser/sts/class_init-expected.txt create mode 100644 test/parser/sts/class_init.sts create mode 100644 test/parser/sts/class_instance-expected.txt create mode 100644 test/parser/sts/class_instance.sts create mode 100644 test/parser/sts/class_instance_creation-expected.txt create mode 100644 test/parser/sts/class_instance_creation.sts create mode 100644 test/parser/sts/class_instance_initializer-expected.txt create mode 100644 test/parser/sts/class_instance_initializer.sts create mode 100644 test/parser/sts/class_property_access-expected.txt create mode 100644 test/parser/sts/class_property_access.sts create mode 100644 test/parser/sts/class_static_initializer-expected.txt create mode 100644 test/parser/sts/class_static_initializer.sts create mode 100644 test/parser/sts/classes-expected.txt create mode 100644 test/parser/sts/classes.sts create mode 100644 test/parser/sts/comment_block-expected.txt create mode 100644 test/parser/sts/comment_block.sts create mode 100644 test/parser/sts/comment_line-expected.txt create mode 100644 test/parser/sts/comment_line.sts create mode 100644 test/parser/sts/const-expected.txt create mode 100644 test/parser/sts/const.sts create mode 100644 test/parser/sts/const_enum-expected.txt create mode 100644 test/parser/sts/const_enum.sts create mode 100644 test/parser/sts/constructor_test-expected.txt create mode 100644 test/parser/sts/constructor_test.sts create mode 100644 test/parser/sts/constructors-expected.txt create mode 100644 test/parser/sts/constructors.sts create mode 100644 test/parser/sts/continue-expected.txt create mode 100644 test/parser/sts/continue.sts create mode 100644 test/parser/sts/decl_infer-expected.txt create mode 100644 test/parser/sts/decl_infer.sts create mode 100644 test/parser/sts/defer-plus-expected.txt create mode 100644 test/parser/sts/defer-plus.sts create mode 100644 test/parser/sts/empty_class-expected.txt create mode 100644 test/parser/sts/empty_class.sts create mode 100644 test/parser/sts/empty_statement-expected.txt create mode 100644 test/parser/sts/empty_statement.sts create mode 100644 test/parser/sts/enum-expected.txt create mode 100644 test/parser/sts/enum.sts create mode 100644 test/parser/sts/enum_with_class_behavior-expected.txt create mode 100644 test/parser/sts/enum_with_class_behavior.sts create mode 100644 test/parser/sts/exports-expected.txt create mode 100644 test/parser/sts/exports.sts create mode 100644 test/parser/sts/field_decl-expected.txt create mode 100644 test/parser/sts/field_decl.sts create mode 100644 test/parser/sts/fields-expected.txt create mode 100644 test/parser/sts/fields.sts create mode 100644 test/parser/sts/final_empty_class-expected.txt create mode 100644 test/parser/sts/final_empty_class.sts create mode 100644 test/parser/sts/for_of-expected.txt create mode 100644 test/parser/sts/for_of.sts create mode 100644 test/parser/sts/for_with_break-expected.txt create mode 100644 test/parser/sts/for_with_break.sts create mode 100644 test/parser/sts/function-expected.txt create mode 100644 test/parser/sts/function.sts create mode 100644 test/parser/sts/function_decl-expected.txt create mode 100644 test/parser/sts/function_decl.sts create mode 100644 test/parser/sts/generic_function-expected.txt create mode 100644 test/parser/sts/generic_function.sts create mode 100644 test/parser/sts/generics_1-expected.txt create mode 100644 test/parser/sts/generics_1.sts create mode 100644 test/parser/sts/identifier-expected.txt create mode 100644 test/parser/sts/identifier.sts create mode 100644 test/parser/sts/if-expected.txt create mode 100644 test/parser/sts/if.sts create mode 100644 test/parser/sts/ifs-expected.txt create mode 100644 test/parser/sts/ifs.sts create mode 100644 test/parser/sts/index_expressions-expected.txt create mode 100644 test/parser/sts/index_expressions.sts create mode 100644 test/parser/sts/inheritance-expected.txt create mode 100644 test/parser/sts/inheritance.sts create mode 100644 test/parser/sts/instanceof-expected.txt create mode 100644 test/parser/sts/instanceof.sts create mode 100644 test/parser/sts/interface-expected.txt create mode 100644 test/parser/sts/interface.sts create mode 100644 test/parser/sts/interfaces-expected.txt create mode 100644 test/parser/sts/interfaces.sts create mode 100644 test/parser/sts/labeled-expected.txt create mode 100644 test/parser/sts/labeled.sts create mode 100644 test/parser/sts/lexer001-expected.txt create mode 100644 test/parser/sts/lexer001.sts create mode 100644 test/parser/sts/lexer002-expected.txt create mode 100644 test/parser/sts/lexer002.sts create mode 100644 test/parser/sts/literals-expected.txt create mode 100644 test/parser/sts/literals.sts create mode 100644 test/parser/sts/localClassIsPermitted-expected.txt create mode 100644 test/parser/sts/localClassIsPermitted.sts create mode 100644 test/parser/sts/loops-expected.txt create mode 100644 test/parser/sts/loops.sts create mode 100644 test/parser/sts/method_empty-expected.txt create mode 100644 test/parser/sts/method_empty.sts create mode 100644 test/parser/sts/method_full-expected.txt create mode 100644 test/parser/sts/method_full.sts create mode 100644 test/parser/sts/methods-expected.txt create mode 100644 test/parser/sts/methods.sts create mode 100644 test/parser/sts/named_types-expected.txt create mode 100644 test/parser/sts/named_types.sts create mode 100644 test/parser/sts/new_expressions-expected.txt create mode 100644 test/parser/sts/new_expressions.sts create mode 100644 test/parser/sts/null-expected.txt create mode 100644 test/parser/sts/null.sts create mode 100644 test/parser/sts/null_invalid-expected.txt create mode 100644 test/parser/sts/null_invalid.sts create mode 100644 test/parser/sts/object-expected.txt create mode 100644 test/parser/sts/object.sts create mode 100644 test/parser/sts/override_method-expected.txt create mode 100644 test/parser/sts/override_method.sts create mode 100644 test/parser/sts/panic-if-expected.txt create mode 100644 test/parser/sts/panic-if.sts create mode 100644 test/parser/sts/panic-statement-expected.txt create mode 100644 test/parser/sts/panic-statement.sts create mode 100644 test/parser/sts/parentheses_expression_value-expected.txt create mode 100644 test/parser/sts/parentheses_expression_value.sts create mode 100644 test/parser/sts/predefined_non_primitive_types-expected.txt create mode 100644 test/parser/sts/predefined_non_primitive_types.sts create mode 100644 test/parser/sts/predefined_types-expected.txt create mode 100644 test/parser/sts/predefined_types.sts create mode 100644 test/parser/sts/regression-target-type-context-expected.txt create mode 100644 test/parser/sts/regression-target-type-context.sts create mode 100644 test/parser/sts/return-expected.txt create mode 100644 test/parser/sts/return.sts create mode 100644 test/parser/sts/scoped_decl-expected.txt create mode 100644 test/parser/sts/scoped_decl.sts create mode 100644 test/parser/sts/simple_types-expected.txt create mode 100644 test/parser/sts/simple_types.sts create mode 100644 test/parser/sts/special_signatures-expected.txt create mode 100644 test/parser/sts/special_signatures.sts create mode 100644 test/parser/sts/string-expected.txt create mode 100644 test/parser/sts/string.sts create mode 100644 test/parser/sts/switch-expected.txt create mode 100644 test/parser/sts/switch.sts create mode 100644 test/parser/sts/switch2-expected.txt create mode 100644 test/parser/sts/switch2.sts create mode 100644 test/parser/sts/ternary-expected.txt create mode 100644 test/parser/sts/ternary.sts create mode 100644 test/parser/sts/test_enum-expected.txt create mode 100644 test/parser/sts/test_enum.sts create mode 100644 test/parser/sts/test_interface-expected.txt create mode 100644 test/parser/sts/test_interface.sts create mode 100644 test/parser/sts/topLevelStaticClass-expected.txt create mode 100644 test/parser/sts/topLevelStaticClass.sts create mode 100644 test/parser/sts/trap-expected.txt create mode 100644 test/parser/sts/trap-missing-catch-expected.txt create mode 100644 test/parser/sts/trap-missing-catch.sts create mode 100644 test/parser/sts/trap.sts create mode 100644 test/parser/sts/type_cast-expected.txt create mode 100644 test/parser/sts/type_cast.sts create mode 100644 test/parser/sts/type_references-expected.txt create mode 100644 test/parser/sts/type_references.sts create mode 100644 test/parser/sts/types_decls-expected.txt create mode 100644 test/parser/sts/types_decls.sts create mode 100644 test/parser/sts/unary_op-expected.txt create mode 100644 test/parser/sts/unary_op.sts create mode 100644 test/parser/sts/unary_operations-expected.txt create mode 100644 test/parser/sts/unary_operations.sts create mode 100644 test/parser/sts/var_declare-expected.txt create mode 100644 test/parser/sts/var_declare.sts create mode 100644 test/parser/sts/void-expected.txt create mode 100644 test/parser/sts/void.sts create mode 100755 test/runner.py create mode 100644 test/runtime/sts/AccessBinaryTrees.sts create mode 100644 test/runtime/sts/AccessFannkuch.sts create mode 100644 test/runtime/sts/AccessNSieve.sts create mode 100644 test/runtime/sts/Bitops3BitBitsInByte.sts create mode 100644 test/runtime/sts/BitopsBitsInByte.sts create mode 100644 test/runtime/sts/BitopsBitwiseAnd.sts create mode 100644 test/runtime/sts/BitopsNSieveBits.sts create mode 100644 test/runtime/sts/ClassNewInstance.sts create mode 100644 test/runtime/sts/ControlFlowRecursive.sts create mode 100644 test/runtime/sts/MathPartialSums.sts create mode 100644 test/runtime/sts/MathSpectralNorm.sts create mode 100644 test/runtime/sts/Morph3d.sts create mode 100644 test/runtime/sts/cast.sts create mode 100644 test/runtime/sts/char-type.sts create mode 100644 test/runtime/sts/class-init.sts create mode 100644 test/runtime/sts/count.sts create mode 100644 test/runtime/sts/generics_1.sts create mode 100644 test/runtime/sts/skippedTest.sts create mode 100644 test/stsskiplist.txt diff --git a/BUILD.gn b/BUILD.gn index 714417c16..a4ab0332e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -25,8 +25,14 @@ config("libes2panda_public_config") { libes2panda_sources = [ "es2panda.cpp", + "binder/ASBinder.cpp", + "binder/TSBinder.cpp", + "binder/TypedBinder.cpp", + "binder/STSBinder.cpp", + "binder/JSBinder.cpp", "binder/binder.cpp", "binder/declaration.cpp", + "binder/recordTable.cpp", "binder/scope.cpp", "binder/variable.cpp", "compiler/base/catchTable.cpp", @@ -38,26 +44,36 @@ libes2panda_sources = [ "compiler/base/literals.cpp", "compiler/base/lreference.cpp", "compiler/base/optionalChain.cpp", + "compiler/core/codeGen.cpp", + "compiler/core/compileJob.cpp", "compiler/core/compileQueue.cpp", "compiler/core/compilerContext.cpp", "compiler/core/compilerImpl.cpp", "compiler/core/dynamicContext.cpp", "compiler/core/emitter.cpp", + "compiler/core/JSemitter.cpp", "compiler/core/envScope.cpp", "compiler/core/function.cpp", - "compiler/core/inlineCache.cpp", "compiler/core/labelTarget.cpp", "compiler/core/moduleContext.cpp", "compiler/core/pandagen.cpp", + "compiler/core/programElement.cpp", "compiler/core/regAllocator.cpp", "compiler/core/regScope.cpp", + "compiler/core/regSpiller.cpp", + "compiler/core/STSemitter.cpp", + "compiler/core/STSGen.cpp", + "compiler/core/STSfunction.cpp", "compiler/core/switchBuilder.cpp", + "compiler/core/targetTypeContext.cpp", + "compiler/core/vReg.cpp", "compiler/debugger/debuginfoDumper.cpp", "compiler/function/asyncFunctionBuilder.cpp", "compiler/function/asyncGeneratorFunctionBuilder.cpp", "compiler/function/functionBuilder.cpp", "compiler/function/generatorFunctionBuilder.cpp", "ir/astDump.cpp", + "ir/astNode.cpp", "ir/irnode.cpp", "ir/base/catchClause.cpp", "ir/base/classElement.cpp", @@ -71,6 +87,10 @@ libes2panda_sources = [ "ir/base/scriptFunction.cpp", "ir/base/spreadElement.cpp", "ir/base/templateElement.cpp", + "ir/base/tsIndexSignature.cpp", + "ir/base/tsMethodSignature.cpp", + "ir/base/tsPropertySignature.cpp", + "ir/base/tsSignatureDeclaration.cpp", "ir/expression.cpp", "ir/expressions/arrayExpression.cpp", "ir/expressions/arrowFunctionExpression.cpp", @@ -88,6 +108,7 @@ libes2panda_sources = [ "ir/expressions/literal.cpp", "ir/expressions/literals/bigIntLiteral.cpp", "ir/expressions/literals/booleanLiteral.cpp", + "ir/expressions/literals/charLiteral.cpp", "ir/expressions/literals/nullLiteral.cpp", "ir/expressions/literals/numberLiteral.cpp", "ir/expressions/literals/regExpLiteral.cpp", @@ -113,11 +134,13 @@ libes2panda_sources = [ "ir/module/importNamespaceSpecifier.cpp", "ir/module/importSpecifier.cpp", "ir/statement.cpp", + "ir/statements/assertStatement.cpp", "ir/statements/blockStatement.cpp", "ir/statements/breakStatement.cpp", "ir/statements/classDeclaration.cpp", "ir/statements/continueStatement.cpp", "ir/statements/debuggerStatement.cpp", + "ir/statements/deferStatement.cpp", "ir/statements/doWhileStatement.cpp", "ir/statements/emptyStatement.cpp", "ir/statements/expressionStatement.cpp", @@ -128,9 +151,11 @@ libes2panda_sources = [ "ir/statements/ifStatement.cpp", "ir/statements/labelledStatement.cpp", "ir/statements/loopStatement.cpp", + "ir/statements/panicStatement.cpp", "ir/statements/returnStatement.cpp", "ir/statements/switchCaseStatement.cpp", "ir/statements/switchStatement.cpp", + "ir/statements/trapStatement.cpp", "ir/statements/throwStatement.cpp", "ir/statements/tryStatement.cpp", "ir/statements/variableDeclaration.cpp", @@ -152,7 +177,6 @@ libes2panda_sources = [ "ir/ts/tsFunctionType.cpp", "ir/ts/tsImportEqualsDeclaration.cpp", "ir/ts/tsImportType.cpp", - "ir/ts/tsIndexSignature.cpp", "ir/ts/tsIndexedAccessType.cpp", "ir/ts/tsInferType.cpp", "ir/ts/tsInterfaceBody.cpp", @@ -161,7 +185,6 @@ libes2panda_sources = [ "ir/ts/tsIntersectionType.cpp", "ir/ts/tsLiteralType.cpp", "ir/ts/tsMappedType.cpp", - "ir/ts/tsMethodSignature.cpp", "ir/ts/tsModuleBlock.cpp", "ir/ts/tsModuleDeclaration.cpp", "ir/ts/tsNamedTupleMember.cpp", @@ -172,9 +195,7 @@ libes2panda_sources = [ "ir/ts/tsObjectKeyword.cpp", "ir/ts/tsParameterProperty.cpp", "ir/ts/tsParenthesizedType.cpp", - "ir/ts/tsPropertySignature.cpp", "ir/ts/tsQualifiedName.cpp", - "ir/ts/tsSignatureDeclaration.cpp", "ir/ts/tsStringKeyword.cpp", "ir/ts/tsThisType.cpp", "ir/ts/tsTupleType.cpp", @@ -192,61 +213,116 @@ libes2panda_sources = [ "ir/ts/tsUnionType.cpp", "ir/ts/tsUnknownKeyword.cpp", "ir/ts/tsVoidKeyword.cpp", + "ir/sts/stsClassLiteral.cpp", + "ir/sts/stsNewArrayInstanceExpression.cpp", + "ir/sts/stsNewClassInstanceExpression.cpp", + "ir/sts/stsNewMultiDimArrayInstanceExpression.cpp", + "ir/sts/stsPackageDeclaration.cpp", + "ir/sts/stsPrimitiveType.cpp", + "ir/sts/stsScript.cpp", + "ir/sts/stsTryExpression.cpp", + "ir/sts/stsTypeReference.cpp", + "ir/sts/stsTypeReferencePart.cpp", + "ir/sts/stsWildcardType.cpp", + "lexer/ASLexer.cpp", + "lexer/keywords.cpp", "lexer/keywordsUtil.cpp", "lexer/lexer.cpp", + "lexer/STSLexer.cpp", + "lexer/TSLexer.cpp", "lexer/regexp/regexp.cpp", + "lexer/token/number.cpp", "lexer/token/sourceLocation.cpp", "lexer/token/token.cpp", "parser/context/classPrivateContext.cpp", "parser/context/parserContext.cpp", "parser/expressionParser.cpp", + "parser/ASparser.cpp", + "parser/JSparser.cpp", "parser/parserImpl.cpp", + "parser/STSparser.cpp", + "parser/TSparser.cpp", + "parser/TypedParser.cpp", "parser/program/program.cpp", "parser/statementParser.cpp", - "typescript/checker.cpp", - "typescript/core/binaryLikeExpression.cpp", - "typescript/core/checkerContext.cpp", - "typescript/core/destructuringContext.cpp", - "typescript/core/function.cpp", - "typescript/core/helpers.cpp", - "typescript/core/object.cpp", - "typescript/core/typeCreation.cpp", - "typescript/core/typeElaborationContext.cpp", - "typescript/core/typeRelation.cpp", - "typescript/core/util.cpp", - "typescript/types/anyType.cpp", - "typescript/types/arrayType.cpp", - "typescript/types/bigintLiteralType.cpp", - "typescript/types/bigintType.cpp", - "typescript/types/booleanLiteralType.cpp", - "typescript/types/booleanType.cpp", - "typescript/types/constructorType.cpp", - "typescript/types/enumLiteralType.cpp", - "typescript/types/enumType.cpp", - "typescript/types/functionType.cpp", - "typescript/types/globalTypesHolder.cpp", - "typescript/types/indexInfo.cpp", - "typescript/types/interfaceType.cpp", - "typescript/types/neverType.cpp", - "typescript/types/nonPrimitiveType.cpp", - "typescript/types/nullType.cpp", - "typescript/types/numberLiteralType.cpp", - "typescript/types/numberType.cpp", - "typescript/types/objectDescriptor.cpp", - "typescript/types/objectLiteralType.cpp", - "typescript/types/objectType.cpp", - "typescript/types/signature.cpp", - "typescript/types/stringLiteralType.cpp", - "typescript/types/stringType.cpp", - "typescript/types/tupleType.cpp", - "typescript/types/type.cpp", - "typescript/types/typeParameter.cpp", - "typescript/types/typeReference.cpp", - "typescript/types/typeRelation.cpp", - "typescript/types/undefinedType.cpp", - "typescript/types/unionType.cpp", - "typescript/types/unknownType.cpp", - "typescript/types/voidType.cpp", + "checker/checker.cpp", + "checker/checkerContext.cpp", + "checker/STSchecker.cpp", + "checker/TSchecker.cpp", + "checker/ASchecker.cpp", + "checker/JSchecker.cpp", + "checker/sts/aliveAnalyzer.cpp", + "checker/sts/arithmetic.cpp", + "checker/sts/baseAnalyzer.cpp", + "checker/sts/boxingConverter.cpp", + "checker/sts/function.cpp", + "checker/sts/helpers.cpp", + "checker/sts/narrowingConverter.cpp", + "checker/sts/narrowingWideningConverter.cpp", + "checker/sts/object.cpp", + "checker/sts/primitiveWrappers.cpp", + "checker/sts/typeConverter.cpp", + "checker/sts/typeCreation.cpp", + "checker/sts/typeRelationContext.cpp", + "checker/sts/unboxingConverter.cpp", + "checker/sts/wideningConverter.cpp", + "checker/ts/binaryLikeExpression.cpp", + "checker/ts/destructuringContext.cpp", + "checker/ts/function.cpp", + "checker/ts/helpers.cpp", + "checker/ts/object.cpp", + "checker/ts/typeCreation.cpp", + "checker/ts/typeElaborationContext.cpp", + "checker/ts/util.cpp", + "checker/types/signature.cpp", + "checker/types/type.cpp", + "checker/types/typeRelation.cpp", + "checker/types/globalTypesHolder.cpp", + "checker/types/sts/byteType.cpp", + "checker/types/sts/charType.cpp", + "checker/types/sts/doubleType.cpp", + "checker/types/sts/floatType.cpp", + "checker/types/sts/intType.cpp", + "checker/types/sts/longType.cpp", + "checker/types/sts/shortType.cpp", + "checker/types/sts/stsArrayType.cpp", + "checker/types/sts/stsBooleanType.cpp", + "checker/types/sts/stsFunctionType.cpp", + "checker/types/sts/stsObjectType.cpp", + "checker/types/sts/stsStringType.cpp", + "checker/types/sts/stsTypeParameter.cpp", + "checker/types/sts/stsTypeReference.cpp", + "checker/types/sts/stsVoidType.cpp", + "checker/types/sts/wildcardType.cpp", + "checker/types/ts/anyType.cpp", + "checker/types/ts/arrayType.cpp", + "checker/types/ts/bigintLiteralType.cpp", + "checker/types/ts/bigintType.cpp", + "checker/types/ts/booleanLiteralType.cpp", + "checker/types/ts/booleanType.cpp", + "checker/types/ts/constructorType.cpp", + "checker/types/ts/enumLiteralType.cpp", + "checker/types/ts/enumType.cpp", + "checker/types/ts/functionType.cpp", + "checker/types/ts/indexInfo.cpp", + "checker/types/ts/interfaceType.cpp", + "checker/types/ts/neverType.cpp", + "checker/types/ts/nonPrimitiveType.cpp", + "checker/types/ts/nullType.cpp", + "checker/types/ts/numberLiteralType.cpp", + "checker/types/ts/numberType.cpp", + "checker/types/ts/objectDescriptor.cpp", + "checker/types/ts/objectLiteralType.cpp", + "checker/types/ts/objectType.cpp", + "checker/types/ts/stringLiteralType.cpp", + "checker/types/ts/stringType.cpp", + "checker/types/ts/tupleType.cpp", + "checker/types/ts/typeParameter.cpp", + "checker/types/ts/typeReference.cpp", + "checker/types/ts/undefinedType.cpp", + "checker/types/ts/unionType.cpp", + "checker/types/ts/unknownType.cpp", + "checker/types/ts/voidType.cpp", "util/bitset.cpp", "util/helpers.cpp", "util/ustring.cpp", @@ -277,8 +353,7 @@ ohos_shared_library("libes2panda") { deps = [ ":isa_gen_es2panda_isa_h", ":isa_gen_es2panda_formats_h", - ":es2panda_lexer_keywords_h", - ":es2panda_lexer_keywords_map_h", + ":gen_es2panda_keywords_h", "$ark_root/assembler:libarkassembler", "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", @@ -299,8 +374,8 @@ ohos_static_library("libes2panda_frontend_static") { deps = [ ":isa_gen_es2panda_isa_h", ":isa_gen_es2panda_formats_h", - ":es2panda_lexer_keywords_h", - ":es2panda_lexer_keywords_map_h", + ":gen_es2panda_lexer_keywords_h", + ":gen_es2panda_compiler_signatures_h", "$ark_root/assembler:libarkassembler_frontend_static", "$ark_root/libpandabase:libarkbase_frontend_static", "$ark_root/libpandafile:libarkfile_frontend_static", @@ -318,20 +393,26 @@ ark_isa_gen("isa_gen_es2panda") { destination = "$target_gen_dir/generated" } -action("es2panda_lexer_keywords_h") { - script = "lexer/scripts/keywords.rb" - outputs = [ "$target_gen_dir/generated/keywords.h" ] - args = [ - rebase_path("lexer/templates/keywords.h.erb", root_build_dir), - rebase_path("$target_gen_dir/generated/keywords.h", root_build_dir), +ark_gen("gen_es2panda_lexer") { + data = "lexer/scripts/keywords.yaml" + template_files = [ + "keywords.h.erb", + ] + sources = "lexer/templates" + destination = "$target_gen_dir/generated" + requires = [ + "lexer/scripts/keywords.rb", ] } -action("es2panda_lexer_keywords_map_h") { - script = "lexer/scripts/keywords.rb" - outputs = [ "$target_gen_dir/generated/keywordsMap.h" ] - args = [ - rebase_path("lexer/templates/keywordsMap.h.erb", root_build_dir), - rebase_path("$target_gen_dir/generated/keywordsMap.h", root_build_dir), +ark_gen("gen_es2panda_compiler") { + data = "compiler/scripts/signatures.yaml" + template_files = [ + "signatures.h.erb", + ] + sources = "compiler/templates" + destination = "$target_gen_dir/generated" + requires = [ + "compiler/scripts/signatures.rb", ] } diff --git a/CMakeLists.txt b/CMakeLists.txt index 3113e256f..c1eb6427c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(GENERATED_DIR ${OUTPUT_DIR}/generated) set(GENERATED_STAMP ${OUTPUT_DIR}/gen_dir.stamp) -add_custom_target(es2panda-gen) add_custom_command( OUTPUT ${GENERATED_STAMP} @@ -40,35 +39,36 @@ panda_isa_gen( EXTRA_DEPENDENCIES ${GENERATED_STAMP} ) -add_dependencies(es2panda-gen isa_gen_es2panda) - -function(gen_keywords TEMPLATE OUT_DIR) - set(TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/lexer/templates/${TEMPLATE}) - - string(REGEX REPLACE "\.erb$" "" NAME ${TEMPLATE}) - string(REPLACE "\." "_" CUSTOM_TARGET ${NAME}) - string(REPLACE "/" "_" CUSTOM_TARGET ${CUSTOM_TARGET}) - set(CUSTOM_TARGET "panda_es2panda_parser_gen_${CUSTOM_TARGET}") - - set(OUT_FILE ${OUT_DIR}/${NAME}) - set(GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.rb) - - add_custom_command(OUTPUT ${OUT_FILE} - COMMAND ruby ${GENERATOR} ${TEMPLATE_FILE} ${OUT_FILE} - DEPENDS ${GENERATED_STAMP} ${GENERATOR} ${TEMPLATE_FILE} - ) - - add_custom_target(${CUSTOM_TARGET} DEPENDS ${OUT_FILE}) - add_dependencies(es2panda-gen ${CUSTOM_TARGET}) -endfunction() +panda_gen( + DATA ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.yaml + TARGET_NAME es2panda_keywords + TEMPLATES keywords.h.erb + REQUIRES + ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.rb + SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lexer/templates + DESTINATION ${GENERATED_DIR} +) -gen_keywords(keywords.h.erb ${GENERATED_DIR}) -gen_keywords(keywordsMap.h.erb ${GENERATED_DIR}) +panda_gen( + DATA ${CMAKE_CURRENT_SOURCE_DIR}/compiler/scripts/signatures.yaml + TARGET_NAME es2panda_signatures + TEMPLATES signatures.h.erb + REQUIRES + ${CMAKE_CURRENT_SOURCE_DIR}/compiler/scripts/signatures.rb + SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/compiler/templates + DESTINATION ${GENERATED_DIR} +) set(ES2PANDA_LIB_SRC es2panda.cpp + binder/ASBinder.cpp + binder/TSBinder.cpp + binder/TypedBinder.cpp + binder/STSBinder.cpp + binder/JSBinder.cpp binder/binder.cpp binder/declaration.cpp + binder/recordTable.cpp binder/scope.cpp binder/variable.cpp compiler/base/catchTable.cpp @@ -80,26 +80,36 @@ set(ES2PANDA_LIB_SRC compiler/base/literals.cpp compiler/base/lreference.cpp compiler/base/optionalChain.cpp + compiler/core/codeGen.cpp + compiler/core/compileJob.cpp compiler/core/compileQueue.cpp compiler/core/compilerContext.cpp compiler/core/compilerImpl.cpp compiler/core/dynamicContext.cpp compiler/core/emitter.cpp + compiler/core/JSemitter.cpp compiler/core/envScope.cpp compiler/core/function.cpp - compiler/core/inlineCache.cpp compiler/core/labelTarget.cpp compiler/core/moduleContext.cpp compiler/core/pandagen.cpp + compiler/core/programElement.cpp compiler/core/regAllocator.cpp compiler/core/regScope.cpp + compiler/core/regSpiller.cpp + compiler/core/STSemitter.cpp + compiler/core/STSGen.cpp + compiler/core/STSfunction.cpp compiler/core/switchBuilder.cpp + compiler/core/targetTypeContext.cpp + compiler/core/vReg.cpp compiler/debugger/debuginfoDumper.cpp compiler/function/asyncFunctionBuilder.cpp compiler/function/asyncGeneratorFunctionBuilder.cpp compiler/function/functionBuilder.cpp compiler/function/generatorFunctionBuilder.cpp ir/astDump.cpp + ir/astNode.cpp ir/irnode.cpp ir/base/catchClause.cpp ir/base/classElement.cpp @@ -113,6 +123,10 @@ set(ES2PANDA_LIB_SRC ir/base/scriptFunction.cpp ir/base/spreadElement.cpp ir/base/templateElement.cpp + ir/base/tsIndexSignature.cpp + ir/base/tsMethodSignature.cpp + ir/base/tsPropertySignature.cpp + ir/base/tsSignatureDeclaration.cpp ir/expression.cpp ir/expressions/arrayExpression.cpp ir/expressions/arrowFunctionExpression.cpp @@ -130,6 +144,7 @@ set(ES2PANDA_LIB_SRC ir/expressions/literal.cpp ir/expressions/literals/bigIntLiteral.cpp ir/expressions/literals/booleanLiteral.cpp + ir/expressions/literals/charLiteral.cpp ir/expressions/literals/nullLiteral.cpp ir/expressions/literals/numberLiteral.cpp ir/expressions/literals/regExpLiteral.cpp @@ -155,11 +170,13 @@ set(ES2PANDA_LIB_SRC ir/module/importNamespaceSpecifier.cpp ir/module/importSpecifier.cpp ir/statement.cpp + ir/statements/assertStatement.cpp ir/statements/blockStatement.cpp ir/statements/breakStatement.cpp ir/statements/classDeclaration.cpp ir/statements/continueStatement.cpp ir/statements/debuggerStatement.cpp + ir/statements/deferStatement.cpp ir/statements/doWhileStatement.cpp ir/statements/emptyStatement.cpp ir/statements/expressionStatement.cpp @@ -170,16 +187,29 @@ set(ES2PANDA_LIB_SRC ir/statements/ifStatement.cpp ir/statements/labelledStatement.cpp ir/statements/loopStatement.cpp + ir/statements/panicStatement.cpp ir/statements/returnStatement.cpp ir/statements/switchCaseStatement.cpp ir/statements/switchStatement.cpp ir/statements/throwStatement.cpp + ir/statements/trapStatement.cpp ir/statements/tryStatement.cpp ir/statements/variableDeclaration.cpp ir/statements/variableDeclarator.cpp ir/statements/whileStatement.cpp ir/as/namedType.cpp ir/as/prefixAssertionExpression.cpp + ir/sts/stsClassLiteral.cpp + ir/sts/stsNewArrayInstanceExpression.cpp + ir/sts/stsNewClassInstanceExpression.cpp + ir/sts/stsNewMultiDimArrayInstanceExpression.cpp + ir/sts/stsPackageDeclaration.cpp + ir/sts/stsPrimitiveType.cpp + ir/sts/stsScript.cpp + ir/sts/stsTryExpression.cpp + ir/sts/stsTypeReference.cpp + ir/sts/stsTypeReferencePart.cpp + ir/sts/stsWildcardType.cpp ir/ts/tsAnyKeyword.cpp ir/ts/tsArrayType.cpp ir/ts/tsAsExpression.cpp @@ -194,7 +224,6 @@ set(ES2PANDA_LIB_SRC ir/ts/tsFunctionType.cpp ir/ts/tsImportEqualsDeclaration.cpp ir/ts/tsImportType.cpp - ir/ts/tsIndexSignature.cpp ir/ts/tsIndexedAccessType.cpp ir/ts/tsInferType.cpp ir/ts/tsInterfaceBody.cpp @@ -203,7 +232,6 @@ set(ES2PANDA_LIB_SRC ir/ts/tsIntersectionType.cpp ir/ts/tsLiteralType.cpp ir/ts/tsMappedType.cpp - ir/ts/tsMethodSignature.cpp ir/ts/tsModuleBlock.cpp ir/ts/tsModuleDeclaration.cpp ir/ts/tsNamedTupleMember.cpp @@ -214,9 +242,7 @@ set(ES2PANDA_LIB_SRC ir/ts/tsObjectKeyword.cpp ir/ts/tsParameterProperty.cpp ir/ts/tsParenthesizedType.cpp - ir/ts/tsPropertySignature.cpp ir/ts/tsQualifiedName.cpp - ir/ts/tsSignatureDeclaration.cpp ir/ts/tsStringKeyword.cpp ir/ts/tsThisType.cpp ir/ts/tsTupleType.cpp @@ -234,68 +260,112 @@ set(ES2PANDA_LIB_SRC ir/ts/tsUnionType.cpp ir/ts/tsUnknownKeyword.cpp ir/ts/tsVoidKeyword.cpp + lexer/ASLexer.cpp + lexer/keywords.cpp lexer/keywordsUtil.cpp lexer/lexer.cpp + lexer/STSLexer.cpp + lexer/TSLexer.cpp lexer/regexp/regexp.cpp + lexer/token/number.cpp lexer/token/sourceLocation.cpp lexer/token/token.cpp parser/context/classPrivateContext.cpp parser/context/parserContext.cpp parser/expressionParser.cpp + parser/ASparser.cpp + parser/JSparser.cpp parser/parserImpl.cpp + parser/STSparser.cpp + parser/TSparser.cpp + parser/TypedParser.cpp parser/program/program.cpp parser/statementParser.cpp - typescript/checker.cpp - typescript/core/binaryLikeExpression.cpp - typescript/core/checkerContext.cpp - typescript/core/destructuringContext.cpp - typescript/core/function.cpp - typescript/core/helpers.cpp - typescript/core/object.cpp - typescript/core/typeCreation.cpp - typescript/core/typeElaborationContext.cpp - typescript/core/typeRelation.cpp - typescript/core/util.cpp - typescript/types/anyType.cpp - typescript/types/arrayType.cpp - typescript/types/bigintLiteralType.cpp - typescript/types/bigintType.cpp - typescript/types/booleanLiteralType.cpp - typescript/types/booleanType.cpp - typescript/types/constructorType.cpp - typescript/types/enumLiteralType.cpp - typescript/types/enumType.cpp - typescript/types/functionType.cpp - typescript/types/globalTypesHolder.cpp - typescript/types/indexInfo.cpp - typescript/types/interfaceType.cpp - typescript/types/neverType.cpp - typescript/types/nonPrimitiveType.cpp - typescript/types/nullType.cpp - typescript/types/numberLiteralType.cpp - typescript/types/numberType.cpp - typescript/types/objectDescriptor.cpp - typescript/types/objectLiteralType.cpp - typescript/types/objectType.cpp - typescript/types/signature.cpp - typescript/types/stringLiteralType.cpp - typescript/types/stringType.cpp - typescript/types/tupleType.cpp - typescript/types/type.cpp - typescript/types/typeParameter.cpp - typescript/types/typeReference.cpp - typescript/types/typeRelation.cpp - typescript/types/undefinedType.cpp - typescript/types/unionType.cpp - typescript/types/unknownType.cpp - typescript/types/voidType.cpp + checker/checker.cpp + checker/checkerContext.cpp + checker/STSchecker.cpp + checker/TSchecker.cpp + checker/ASchecker.cpp + checker/JSchecker.cpp + checker/sts/aliveAnalyzer.cpp + checker/sts/arithmetic.cpp + checker/sts/baseAnalyzer.cpp + checker/sts/boxingConverter.cpp + checker/sts/function.cpp + checker/sts/helpers.cpp + checker/sts/narrowingConverter.cpp + checker/sts/narrowingWideningConverter.cpp + checker/sts/object.cpp + checker/sts/primitiveWrappers.cpp + checker/sts/typeConverter.cpp + checker/sts/typeCreation.cpp + checker/sts/typeRelationContext.cpp + checker/sts/unboxingConverter.cpp + checker/sts/wideningConverter.cpp + checker/ts/binaryLikeExpression.cpp + checker/ts/destructuringContext.cpp + checker/ts/function.cpp + checker/ts/helpers.cpp + checker/ts/object.cpp + checker/ts/typeCreation.cpp + checker/ts/typeElaborationContext.cpp + checker/ts/util.cpp + checker/types/signature.cpp + checker/types/type.cpp + checker/types/typeRelation.cpp + checker/types/globalTypesHolder.cpp + checker/types/sts/byteType.cpp + checker/types/sts/charType.cpp + checker/types/sts/doubleType.cpp + checker/types/sts/floatType.cpp + checker/types/sts/intType.cpp + checker/types/sts/longType.cpp + checker/types/sts/shortType.cpp + checker/types/sts/stsArrayType.cpp + checker/types/sts/stsBooleanType.cpp + checker/types/sts/stsFunctionType.cpp + checker/types/sts/stsObjectType.cpp + checker/types/sts/stsStringType.cpp + checker/types/sts/stsTypeParameter.cpp + checker/types/sts/stsTypeReference.cpp + checker/types/sts/stsVoidType.cpp + checker/types/sts/wildcardType.cpp + checker/types/ts/anyType.cpp + checker/types/ts/arrayType.cpp + checker/types/ts/bigintLiteralType.cpp + checker/types/ts/bigintType.cpp + checker/types/ts/booleanLiteralType.cpp + checker/types/ts/booleanType.cpp + checker/types/ts/constructorType.cpp + checker/types/ts/enumLiteralType.cpp + checker/types/ts/enumType.cpp + checker/types/ts/functionType.cpp + checker/types/ts/indexInfo.cpp + checker/types/ts/interfaceType.cpp + checker/types/ts/neverType.cpp + checker/types/ts/nonPrimitiveType.cpp + checker/types/ts/nullType.cpp + checker/types/ts/numberLiteralType.cpp + checker/types/ts/numberType.cpp + checker/types/ts/objectDescriptor.cpp + checker/types/ts/objectLiteralType.cpp + checker/types/ts/objectType.cpp + checker/types/ts/stringLiteralType.cpp + checker/types/ts/stringType.cpp + checker/types/ts/tupleType.cpp + checker/types/ts/typeParameter.cpp + checker/types/ts/typeReference.cpp + checker/types/ts/undefinedType.cpp + checker/types/ts/unionType.cpp + checker/types/ts/unknownType.cpp + checker/types/ts/voidType.cpp util/bitset.cpp util/helpers.cpp util/ustring.cpp ) add_library(es2panda-lib ${PANDA_DEFAULT_LIB_TYPE} ${ES2PANDA_LIB_SRC}) -add_dependencies(es2panda-lib es2panda-gen) +add_dependencies(es2panda-lib isa_gen_es2panda es2panda_keywords es2panda_signatures) set(ICU_INCLUDE_DIRS ${PANDA_THIRD_PARTY_SOURCES_DIR}/icu/icu4c/source/common diff --git a/aot/main.cpp b/aot/main.cpp index 778d36a76..ae3d8890f 100644 --- a/aot/main.cpp +++ b/aot/main.cpp @@ -63,13 +63,12 @@ static int GenerateProgram(panda::pandasm::Program *prog, const Options *options panda::Logger::InitializeStdLogging(Logger::LevelFromString(options->LogLevel()), componentMask); if (!panda::pandasm::AsmEmitter::Emit(options->CompilerOutput(), *prog, statp, mapsp, true)) { + std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl; return 1; } panda::bytecodeopt::OPTIONS.SetOptLevel(options->OptLevel()); - // Set default value instead of maximum set in panda::bytecodeopt::SetCompilerOptions() - panda::compiler::OPTIONS.SetCompilerMaxBytecodeSize(panda::compiler::OPTIONS.GetCompilerMaxBytecodeSize()); - panda::bytecodeopt::OptimizeBytecode(prog, mapsp, options->CompilerOutput(), true, true); + panda::bytecodeopt::OptimizeBytecode(prog, mapsp, options->CompilerOutput(), options->IsDynamic(), true); } #endif @@ -83,6 +82,7 @@ static int GenerateProgram(panda::pandasm::Program *prog, const Options *options } if (!panda::pandasm::AsmEmitter::Emit(options->CompilerOutput(), *prog, statp, mapsp, true)) { + std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl; return 1; } @@ -121,7 +121,7 @@ int Run(int argc, const char **argv) es2panda::Compiler compiler(options->Extension(), options->ThreadCount()); es2panda::SourceFile input(options->SourceFile(), options->ParserInput(), options->ParseModule()); - auto *program = compiler.Compile(input, options->CompilerOptions()); + auto program = std::unique_ptr {compiler.Compile(input, options->CompilerOptions())}; if (program == nullptr) { const auto &err = compiler.GetError(); @@ -131,15 +131,13 @@ int Run(int argc, const char **argv) } std::cout << err.TypeString() << ": " << err.Message(); - std::cout << " [" << options->SourceFile() << ":" << err.Line() << ":" << err.Col() << "]" << std::endl; + std::cout << " [" << (err.File().empty() ? options->SourceFile() : err.File()) << ":" << err.Line() << ":" + << err.Col() << "]" << std::endl; return err.ErrorCode(); } - GenerateProgram(program, options.get()); - delete program; - - return 0; + return GenerateProgram(program.get(), options.get()); } } // namespace panda::es2panda::aot diff --git a/aot/options.cpp b/aot/options.cpp index fbce88d98..ae89acb74 100644 --- a/aot/options.cpp +++ b/aot/options.cpp @@ -48,7 +48,7 @@ bool Options::Parse(int argc, const char **argv) // parser panda::PandArg inputExtension("extension", "js", - "Parse the input as the given extension (options: js | ts | as)"); + "Parse the input as the given extension (options: js | ts | as | sts)"); panda::PandArg opModule("module", false, "Parse the input as module"); panda::PandArg opParseOnly("parse-only", false, "Parse the input only"); panda::PandArg opDumpAst("dump-ast", false, "Dump the parsed AST"); @@ -64,6 +64,7 @@ bool Options::Parse(int argc, const char **argv) panda::PandArg opSizeStat("dump-size-stat", false, "Dump size statistics"); panda::PandArg outputFile("output", "", "Compiler binary output (.abc)"); panda::PandArg logLevel("log-level", "error", "Log-level"); + panda::PandArg stdLib("stdlib", "", "Path to standard library"); // tail arguments panda::PandArg inputFile("input", "", "input file"); @@ -83,6 +84,7 @@ bool Options::Parse(int argc, const char **argv) argparser_->Add(&inputExtension); argparser_->Add(&outputFile); argparser_->Add(&logLevel); + argparser_->Add(&stdLib); argparser_->PushBackTail(&inputFile); argparser_->EnableTail(); @@ -137,8 +139,10 @@ bool Options::Parse(int argc, const char **argv) extension_ = es2panda::ScriptExtension::TS; } else if (extension == "as") { extension_ = es2panda::ScriptExtension::AS; + } else if (extension == "sts") { + extension_ = es2panda::ScriptExtension::STS; } else { - errorMsg_ = "Invalid extension (available options: js, ts, as)"; + errorMsg_ = "Invalid extension (available options: js, ts, as, sts)"; return false; } } @@ -163,6 +167,7 @@ bool Options::Parse(int argc, const char **argv) compilerOptions_.dumpDebugInfo = opDumpDebugInfo.GetValue(); compilerOptions_.isDebug = opDebugInfo.GetValue(); compilerOptions_.parseOnly = opParseOnly.GetValue(); + compilerOptions_.stdLib = stdLib.GetValue(); return true; } diff --git a/aot/options.h b/aot/options.h index a3d7d2f0a..0c0d36a32 100644 --- a/aot/options.h +++ b/aot/options.h @@ -119,6 +119,11 @@ public: return (options_ & OptionFlags::SIZE_STAT) != 0; } + bool IsDynamic() const + { + return extension_ != es2panda::ScriptExtension::STS; + } + private: es2panda::ScriptExtension extension_ {es2panda::ScriptExtension::JS}; es2panda::CompilerOptions compilerOptions_ {}; diff --git a/binder/ASBinder.cpp b/binder/ASBinder.cpp new file mode 100644 index 000000000..8a58d1c3e --- /dev/null +++ b/binder/ASBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ASBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/ASBinder.h b/binder/ASBinder.h new file mode 100644 index 000000000..ac6c8b22e --- /dev/null +++ b/binder/ASBinder.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_AS_BINDER_H +#define ES2PANDA_BINDER_AS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class ASBinder : public Binder { +public: + explicit ASBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(ASBinder); + NO_MOVE_SEMANTIC(ASBinder); + ~ASBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::AS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::BINDINGS; + } + + void IdentifierAnalysis() override {} + +private: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/JSBinder.cpp b/binder/JSBinder.cpp new file mode 100644 index 000000000..1e1ead592 --- /dev/null +++ b/binder/JSBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "JSBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/JSBinder.h b/binder/JSBinder.h new file mode 100644 index 000000000..c96c02895 --- /dev/null +++ b/binder/JSBinder.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_JS_BINDER_H +#define ES2PANDA_BINDER_JS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class JSBinder : public Binder { +public: + explicit JSBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(JSBinder); + DEFAULT_MOVE_SEMANTIC(JSBinder); + ~JSBinder() = default; + +private: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/STSBinder.cpp b/binder/STSBinder.cpp new file mode 100644 index 000000000..5bffbe9a3 --- /dev/null +++ b/binder/STSBinder.cpp @@ -0,0 +1,550 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "STSBinder.h" + +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/thisExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/functionExpression.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/statements/functionDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/returnStatement.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsPrimitiveType.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsTypeReferencePart.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterInstantiation.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsClassImplements.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" +#include "plugins/ecmascript/es2panda/ir/module/importDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/module/importSpecifier.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" + +namespace panda::es2panda::binder { + +void STSBinder::IdentifierAnalysis() +{ + ASSERT(program_->Ast()); + ASSERT(scope_ == topScope_); + ASSERT(varScope_ == topScope_); + + recordTable_->SetProgram(program_); + globalRecordTable_.SetClassDefinition(program_->GlobalClass()); + externalRecordTable_.insert({program_, &globalRecordTable_}); + + BuildProgram(); + + ASSERT(globalRecordTable_.ClassDefinition() == program_->GlobalClass()); +} + +void STSBinder::LookupTypeArgumentReferences(ir::STSTypeReference *typeRef) +{ + auto *iter = typeRef->Part(); + + while (iter) { + if (!iter->TypeParams()) { + iter = iter->Previous(); + continue; + } + + for (auto *it : iter->TypeParams()->Params()) { + if (!it->IsSTSTypeReference()) { + continue; + } + + ResolveReference(it); + } + + iter = iter->Previous(); + } +} + +void STSBinder::LookupTypeReference(ir::Identifier *ident) +{ + const auto &name = ident->Name(); + auto *iter = scope_; + + while (iter) { + ScopeFindResult res = iter->Find(name, BindingOptions()); + + if (!res.variable) { + break; + } + + switch (res.variable->Declaration()->Node()->Type()) { + case ir::AstNodeType::TS_INTERFACE_DECLARATION: + case ir::AstNodeType::CLASS_DECLARATION: + case ir::AstNodeType::CLASS_DEFINITION: + case ir::AstNodeType::TS_TYPE_PARAMETER: + case ir::AstNodeType::TS_ENUM_DECLARATION: { + ident->SetVariable(res.variable); + return; + } + default: { + iter = iter->Parent(); + } + } + } + + ThrowUnresolvableType(ident->Start(), name); +} + +void STSBinder::LookupIdentReference(ir::Identifier *ident) +{ + const auto &name = ident->Name(); + ScopeFindResult res = scope_->Find(name, BindingOptions()); + if (res.level != 0) { + ASSERT(res.variable); + + auto *outerFunction = scope_->EnclosingVariableScope()->Node(); + + if ((!outerFunction->IsScriptFunction() || !outerFunction->AsScriptFunction()->IsArrow()) && + !res.variable->IsGlobalVariable() && res.level > 1) { + ThrowInvalidCapture(ident->Start(), name); + } + + res.variable->SetLexical(res.scope); + } + + if (!res.variable) { + return; + } + + if (ident->IsReference() && res.variable->Declaration()->IsLetOrConstDecl() && + !res.variable->HasFlag(VariableFlags::INITIALIZED)) { + ThrowTDZ(ident->Start(), name); + } + + ident->SetVariable(res.variable); +} + +void STSBinder::BuildClassProperty(const ir::ClassProperty *prop) +{ + ResolveReferences(prop); +} + +void STSBinder::InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl) +{ + ScopeFindResult res = scope_->Find(decl->Id()->Name()); + + ASSERT(res.variable && res.variable->Declaration()->IsConstDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); + decl->Id()->SetVariable(res.variable); +} + +void STSBinder::ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl, binder::LocalScope *scope) +{ + auto bctx = BoundContext(recordTable_, decl); + + for (auto *extend : decl->Extends()) { + ResolveReference(extend); + } + + InitializeInterfaceIdent(decl); + + auto scopeCtx = LexicalScope::Enter(this, decl->Scope()); + + for (auto *stmt : decl->Body()->Body()) { + if (!stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + + auto fieldVar = scope->FindLocal(stmt->AsClassProperty()->Id()->Name()); + fieldVar->AddFlag(VariableFlags::INITIALIZED); + } + + for (auto *stmt : decl->Body()->Body()) { + if (stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + } +} + +void STSBinder::BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl) +{ + if (decl->TypeParams()) { + auto typeParamScopeCtx = LexicalScope::Enter(this, decl->TypeParams()->Scope()); + ResolveReferences(decl->TypeParams()); + + auto interfaceScopeCtx = LexicalScope::Enter(this, decl->Scope()); + ResolveInterfaceDeclaration(decl, interfaceScopeCtx.GetScope()); + return; + } + + auto interfaceScopeCtx = LexicalScope::Enter(this, decl->Scope()); + ResolveInterfaceDeclaration(decl, interfaceScopeCtx.GetScope()); +} + +void STSBinder::BuildMethodDefinition(ir::MethodDefinition *methodDef) +{ + ResolveReferences(methodDef); + + if (recordTable_->InterfaceDeclaration() || methodDef->IsStatic() || methodDef->Function()->IsStaticBlock()) { + return; + } + + auto paramScopeCtx = LexicalScope::Enter(this, methodDef->Function()->Scope()->ParamScope()); + auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS); + thisParam->Declaration()->BindNode(thisParam_); +} + +void STSBinder::BuildMemberExpression(ir::MemberExpression *memberExpr) +{ + ResolveReference(memberExpr->Object()); + + if (memberExpr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) { + ResolveReference(memberExpr->Property()); + } +} + +void STSBinder::BuildClassDefinition(ir::ClassDefinition *classDef) +{ + auto bctx = BoundContext(recordTable_, classDef); + + if (classDef->TypeParams()) { + auto scopeCtx = LexicalScope::Enter(this, classDef->TypeParams()->Scope()); + ResolveReferences(classDef->TypeParams()); + + BuildClassDefinitionImpl(classDef); + } else { + BuildClassDefinitionImpl(classDef); + } +} + +void STSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef) +{ + ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); + ASSERT(!res.variable || res.variable->Declaration()->IsClassDecl()); + + auto scopeCtx = LexicalScope::Enter(this, classDef->Scope()); + + if (classDef->Super()) { + ResolveReference(classDef->Super()); + } + + for (auto *impl : classDef->Implements()) { + ResolveReference(impl); + } + + for (auto *stmt : classDef->Body()) { + if (!stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + + auto fieldVar = scopeCtx.GetScope()->FindLocal(stmt->AsClassProperty()->Id()->Name()); + fieldVar->AddFlag(VariableFlags::INITIALIZED); + if (fieldVar->Declaration()->IsConstDecl() && !stmt->AsClassProperty()->Value()) { + fieldVar->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED); + } + } + + for (auto *stmt : classDef->Body()) { + if (stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + } +} + +void STSBinder::HandleCustomNodes(ir::AstNode *childNode) +{ + switch (childNode->Type()) { + case ir::AstNodeType::STS_TYPE_REFERENCE: { + auto *typeRef = childNode->AsSTSTypeReference(); + ASSERT(typeRef->BaseName()->IsReference()); + LookupTypeReference(typeRef->BaseName()); + LookupTypeArgumentReferences(typeRef); + break; + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + BuildInterfaceDeclaration(childNode->AsTSInterfaceDeclaration()); + break; + } + case ir::AstNodeType::EXPORT_NAMED_DECLARATION: { + break; + } + case ir::AstNodeType::IMPORT_DECLARATION: { + BuildImportDeclaration(childNode->AsImportDeclaration()); + break; + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + BuildMemberExpression(childNode->AsMemberExpression()); + break; + } + case ir::AstNodeType::METHOD_DEFINITION: { + BuildMethodDefinition(childNode->AsMethodDefinition()); + break; + } + case ir::AstNodeType::CLASS_STATIC_BLOCK: { + BuildClassStaticBlock(childNode->AsClassStaticBlock()); + break; + } + case ir::AstNodeType::STS_NEW_CLASS_INSTANCE_EXPRESSION: { + BuildSTSNewClassInstanceExpression(childNode->AsSTSNewClassInstanceExpression()); + break; + } + case ir::AstNodeType::DEFER_STATEMENT: { + scope_->AddFlag(ScopeFlags::DEFER_STMT); + ResolveReferences(childNode); + break; + } + default: { + ResolveReferences(childNode); + break; + } + } +} + +void STSBinder::BuildClassStaticBlock(ir::ClassStaticBlock *staticBlock) +{ + const auto &name = staticBlock->Name(); + ScopeFindResult res = scope_->Find(name, BindingOptions()); + staticBlock->Function()->Id()->SetVariable(res.variable); + + ResolveReferences(staticBlock); +} + +bool STSBinder::BuildInternalName([[maybe_unused]] const ir::ScriptFunction *scriptFunc) +{ + std::stringstream ss; + ss << recordTable_->RecordName(); + util::UString className(ss.str(), Allocator()); + + auto *funcScope = scriptFunc->Scope(); + funcScope->BindName(className.View()); + + bool compilable = scriptFunc->Body() && !recordTable_->IsExternal(); + + if (!compilable) { + recordTable_->Signatures().push_back(funcScope); + } + + return compilable; +} + +void STSBinder::BuildFunctionName(const ir::ScriptFunction *func) const +{ + auto *funcScope = func->Scope(); + + std::stringstream ss; + ss << funcScope->Name() << compiler::Signatures::METHOD_SEPARATOR; + + const auto *signature = func->Signature(); + + if (func->IsStaticBlock()) { + ss << compiler::Signatures::CCTOR; + } else { + if (func->IsConstructor()) { + ss << compiler::Signatures::CTOR; + } else { + ss << util::Helpers::FunctionName(Allocator(), func); + } + } + + signature->ToAssemblerType(ss); + + util::UString internalName(ss.str(), Allocator()); + funcScope->BindInternalName(internalName.View()); +} + +void STSBinder::InitImplicitThisParam() +{ + thisParam_ = allocator_->New("this", Allocator()); +} + +void STSBinder::BuildProgram() +{ + for (auto &[package, extPrograms] : program_->ExternalSources()) { + for (auto *extProg : extPrograms) { + BuildExternalProgram(extProg); + } + } + + for (auto *defaultImport : defaultImports_) { + BuildImportDeclaration(defaultImport); + } + + for (auto *stmt_ : program_->Ast()->Statements()) { + ResolveReference(stmt_); + } +} + +void STSBinder::BuildExternalProgram(parser::Program *extProgram) +{ + auto *savedProgram = program_; + auto *savedrecordTable = recordTable_; + auto *savedTopScope_ = topScope_; + + auto *extRecordTable = allocator_->New(allocator_, extProgram, RecordTableFlags::EXTERNAL); + externalRecordTable_.insert({extProgram, extRecordTable}); + + ResetTopScope(extProgram->GlobalScope()); + recordTable_ = extRecordTable; + program_ = extProgram; + + BuildProgram(); + + program_ = savedProgram; + recordTable_ = savedrecordTable; + ResetTopScope(savedTopScope_); +} + +void STSBinder::BuildSTSNewClassInstanceExpression(ir::STSNewClassInstanceExpression *classInstance) +{ + BoundContext boundCtx(recordTable_, classInstance->ClassDefinition()); + ResolveReference(classInstance->GetTypeRef()); + + for (auto *arg : classInstance->GetArguments()) { + ResolveReference(arg); + } + + if (!classInstance->ClassDefinition()) { + return; + } + + ResolveReference(classInstance->ClassDefinition()); +} + +void STSBinder::BuildImportDeclaration(ir::ImportDeclaration *decl) +{ + auto *specifier = decl->Specifiers().front()->AsImportSpecifier(); + + if (!specifier->Imported()->IsTSQualifiedName()) { + return; + } + + auto *importName = specifier->Imported()->AsTSQualifiedName(); + util::StringView fullPath = importName->ToString(allocator_); + + if (*fullPath.Utf8().rbegin() == Binder::STAR_IMPORT.front()) { + HandleStarImport(importName, fullPath); + return; + } + + util::StringView packageName = importName->BaseToString(allocator_); + + if (packageName == program_->GetPackageName()) { + return; + } + + util::StringView imported = importName->ResolveLeftMostQualifiedName()->Right()->Name(); + + auto res = globalRecordTable_.Program()->ExternalSources().find(packageName); + + if (res == globalRecordTable_.Program()->ExternalSources().end()) { + ThrowError(importName->Start(), "Cannot find package."); + } + + ASSERT(!res->second.empty()); + auto &packageNameSpace = res->second.front()->GlobalScope()->Bindings(); + auto bindingRes = packageNameSpace.find(imported); + + if (bindingRes == packageNameSpace.end()) { + ThrowError(importName->Start(), "Cannot find import"); + } + + auto *var = bindingRes->second; + util::StringView localName = imported; + + if (specifier->Local()) { + localName = specifier->Local()->Name(); + } + + if (!topScope_->Bindings().insert({localName, var}).second) { + ThrowError(importName->Start(), "Import already exists."); + } + + return; +} + +void STSBinder::HandleStarImport(ir::TSQualifiedName *importName, util::StringView fullPath) +{ + // Cut ".*" + util::StringView packageName = fullPath.Substr(0, fullPath.Length() - 2); + + if (packageName == program_->GetPackageName()) { + return; + } + + auto res = globalRecordTable_.Program()->ExternalSources().find(packageName); + + if (res == globalRecordTable_.Program()->ExternalSources().end()) { + ThrowError(importName->Start(), "Cannot find package."); + } + + ASSERT(!res->second.empty()); + auto *packageGlobalScope = res->second.front()->GlobalScope(); + + for (auto [bindingName, var] : packageGlobalScope->Bindings()) { + if (bindingName.Is(compiler::Signatures::STS_GLOBAL)) { + auto *classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition(); + ImportGlobalProperties(classDef); + continue; + } + + auto insRes = topScope_->Bindings().insert({bindingName, var}); + if (!insRes.second) { + if (insRes.first->second != var) { + ThrowError(importName->Start(), "Import already exists."); + } + } + } +} + +void STSBinder::ImportGlobalProperties(ir::ClassDefinition *classDef) +{ + auto scopeCtx = LexicalScope::Enter(this, classDef->Scope()); + + for (auto *prop : classDef->Body()) { + auto *classElement = prop->AsClassElement(); + + if (classElement->IsClassStaticBlock()) { + continue; + } + + ASSERT(classElement->IsStatic()); + auto &name = classElement->Id()->Name(); + auto *var = scopeCtx.GetScope()->FindLocal(name); + ASSERT(var); + + auto insRes = topScope_->Bindings().insert({name, var}); + if (!insRes.second) { + if (insRes.first->second != var) { + ThrowError(classElement->Id()->Start(), "Import already exists."); + } + } + } +} + +} // namespace panda::es2panda::binder diff --git a/binder/STSBinder.h b/binder/STSBinder.h new file mode 100644 index 000000000..07a2d4e0c --- /dev/null +++ b/binder/STSBinder.h @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_STS_BINDER_H +#define ES2PANDA_BINDER_STS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/TypedBinder.h" +#include "plugins/ecmascript/es2panda/binder/recordTable.h" + +namespace panda::es2panda::binder { +class STSBinder : public TypedBinder { +public: + explicit STSBinder(ArenaAllocator *allocator) + : TypedBinder(allocator), + globalRecordTable_(allocator, program_, RecordTableFlags::NONE), + recordTable_(&globalRecordTable_), + externalRecordTable_(allocator_->Adapter()), + defaultImports_(allocator_->Adapter()) + { + InitImplicitThisParam(); + } + + NO_COPY_SEMANTIC(STSBinder); + NO_MOVE_SEMANTIC(STSBinder); + ~STSBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::STS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::ALL; + } + + RecordTable *GetRecordTable() + { + return recordTable_; + } + + const RecordTable *GetRecordTable() const + { + return recordTable_; + } + + RecordTable *GetGlobalRecordTable() + { + return &globalRecordTable_; + } + + const RecordTable *GetGlobalRecordTable() const + { + return &globalRecordTable_; + } + + ArenaUnorderedMap &GetExternalRecordTable() + { + return externalRecordTable_; + } + + const ArenaUnorderedMap &GetExternalRecordTable() const + { + return externalRecordTable_; + } + + virtual void HandleCustomNodes(ir::AstNode *childNode) override; + + void IdentifierAnalysis() override; + void BuildClassDefinition(ir::ClassDefinition *classDef) override; + void BuildClassProperty(const ir::ClassProperty *prop) override; + void LookupIdentReference(ir::Identifier *ident) override; + bool BuildInternalName(const ir::ScriptFunction *scriptFunc) override; + + void LookupTypeReference(ir::Identifier *ident); + void LookupTypeArgumentReferences(ir::STSTypeReference *typeRef); + void BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl); + void BuildMemberExpression(ir::MemberExpression *memberExpr); + void BuildMethodDefinition(ir::MethodDefinition *methodDef); + void BuildImportDeclaration(ir::ImportDeclaration *decl); + void BuildClassStaticBlock(ir::ClassStaticBlock *staticBlock); + void BuildSTSNewClassInstanceExpression(ir::STSNewClassInstanceExpression *classDef); + + void ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl, binder::LocalScope *scope); + void InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl); + void BuildExternalProgram(parser::Program *extProgram); + void BuildProgram(); + + void BuildFunctionName(const ir::ScriptFunction *func) const; + + void SetDefaultImports(ArenaVector defaultImports) + { + defaultImports_ = std::move(defaultImports); + } + + static constexpr std::string_view DEFAULT_IMPORT_SOURCE_FILE = ".sts"; + static constexpr std::string_view DEFAULT_IMPORT_SOURCE = R"( +import ets.lang.*; +import ets.io.*; +)"; + +private: + void BuildClassDefinitionImpl(ir::ClassDefinition *classDef); + void InitImplicitThisParam(); + void HandleStarImport(ir::TSQualifiedName *importName, util::StringView fullPath); + void ImportGlobalProperties(ir::ClassDefinition *classDef); + + RecordTable globalRecordTable_; + RecordTable *recordTable_; + ArenaUnorderedMap externalRecordTable_; + ArenaVector defaultImports_; + ir::Identifier *thisParam_; +}; + +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/TSBinder.cpp b/binder/TSBinder.cpp new file mode 100644 index 000000000..c33d7d0ca --- /dev/null +++ b/binder/TSBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TSBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/TSBinder.h b/binder/TSBinder.h new file mode 100644 index 000000000..30b115829 --- /dev/null +++ b/binder/TSBinder.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_TS_BINDER_H +#define ES2PANDA_BINDER_TS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/TypedBinder.h" + +namespace panda::es2panda::binder { +class TSBinder : public TypedBinder { +public: + explicit TSBinder(ArenaAllocator *allocator) : TypedBinder(allocator) {} + + NO_COPY_SEMANTIC(TSBinder); + NO_MOVE_SEMANTIC(TSBinder); + ~TSBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::TS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::ALL; + } + +protected: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/TypedBinder.cpp b/binder/TypedBinder.cpp new file mode 100644 index 000000000..3346b9f61 --- /dev/null +++ b/binder/TypedBinder.cpp @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TypedBinder.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsFunctionType.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsConstructorType.h" + +namespace panda::es2panda::binder { + +void TypedBinder::BuildSignatureDeclarationBaseParams([[maybe_unused]] const ir::AstNode *typeNode) +{ + if (!typeNode) { + return; + } + + Scope *scope = nullptr; + + switch (typeNode->Type()) { + case ir::AstNodeType::TS_FUNCTION_TYPE: { + scope = typeNode->AsTSFunctionType()->Scope(); + break; + } + case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: { + scope = typeNode->AsTSConstructorType()->Scope(); + break; + } + case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { + scope = typeNode->AsTSSignatureDeclaration()->Scope(); + break; + } + case ir::AstNodeType::TS_METHOD_SIGNATURE: { + scope = typeNode->AsTSMethodSignature()->Scope(); + break; + } + default: { + ResolveReferences(typeNode); + return; + } + } + + ASSERT(scope && scope->IsFunctionParamScope()); + + auto scopeCtx = LexicalScope::Enter(this, scope->AsFunctionParamScope()); + ResolveReferences(typeNode); +} + +void TypedBinder::HandleCustomNodes(ir::AstNode *childNode) +{ + switch (childNode->Type()) { + case ir::AstNodeType::TS_FUNCTION_TYPE: + case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: + case ir::AstNodeType::TS_METHOD_SIGNATURE: + case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { + BuildSignatureDeclarationBaseParams(childNode); + break; + } + default: { + ResolveReferences(childNode); + break; + } + } +} +} // namespace panda::es2panda::binder diff --git a/binder/TypedBinder.h b/binder/TypedBinder.h new file mode 100644 index 000000000..813d8aad3 --- /dev/null +++ b/binder/TypedBinder.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_BINDER_TYPED_BINDER_H +#define ES2PANDA_BINDER_TYPED_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class TypedBinder : public Binder { +public: + explicit TypedBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(TypedBinder); + NO_MOVE_SEMANTIC(TypedBinder); + ~TypedBinder() = default; + +protected: + void HandleCustomNodes(ir::AstNode *childNode) override; + void BuildSignatureDeclarationBaseParams([[maybe_unused]] const ir::AstNode *typeNode) override; +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/binder.cpp b/binder/binder.cpp index 682ac0684..4fe0e2f5e 100644 --- a/binder/binder.cpp +++ b/binder/binder.cpp @@ -16,6 +16,7 @@ #include "binder.h" #include "plugins/ecmascript/es2panda/binder/privateBinding.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/tsBinding.h" @@ -24,12 +25,15 @@ #include "plugins/ecmascript/es2panda/ir/astNode.h" #include "plugins/ecmascript/es2panda/ir/base/catchClause.h" #include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" #include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" #include "plugins/ecmascript/es2panda/ir/base/property.h" #include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" #include "plugins/ecmascript/es2panda/ir/expressions/arrayExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/expressions/objectExpression.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" @@ -42,10 +46,17 @@ #include "plugins/ecmascript/es2panda/ir/statements/variableDeclaration.h" #include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" #include "plugins/ecmascript/es2panda/ir/statements/whileStatement.h" +#include "plugins/ecmascript/es2panda/ir/module/exportNamedDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/module/importDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsFunctionType.h" #include "plugins/ecmascript/es2panda/ir/ts/tsConstructorType.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsSignatureDeclaration.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" namespace panda::es2panda::binder { void Binder::InitTopScope() @@ -60,7 +71,7 @@ void Binder::InitTopScope() varScope_ = topScope_; } -ParameterDecl *Binder::AddParamDecl(const ir::AstNode *param) +ParameterDecl *Binder::AddParamDecl(ir::AstNode *param) { ASSERT(scope_->IsFunctionParamScope() || scope_->IsCatchParamScope()); auto [decl, node] = static_cast(scope_)->AddParamDecl(Allocator(), param); @@ -72,24 +83,55 @@ ParameterDecl *Binder::AddParamDecl(const ir::AstNode *param) ThrowRedeclaration(node->Start(), decl->Name()); } -void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) +void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const { - lexer::LineIndex index(program_->SourceCode()); - lexer::SourceLocation loc = index.GetLocation(pos); - std::stringstream ss; ss << "Variable '" << name << "' has already been declared."; - throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col); + ThrowError(pos, ss.str()); +} + +void Binder::ThrowUnresolvableVariable(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot find variable '" << name << "'."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot find type '" << name << "'."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Variable '" << name << "' is accessed before it's initialization."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot capture variable'" << name << "'."; + ThrowError(pos, ss.str()); } void Binder::ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Private field '" << name << "' must be declared in an enclosing class"; + + ThrowError(pos, ss.str()); +} + +void Binder::ThrowError(const lexer::SourcePosition &pos, const std::string_view &msg) const { lexer::LineIndex index(program_->SourceCode()); lexer::SourceLocation loc = index.GetLocation(pos); - std::stringstream ss; - ss << "Private field '" << name << "' must be declared in an enclosing class"; - throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col); + throw Error(ErrorType::SYNTAX, program_->SourceFile().Utf8(), msg, loc.line, loc.col); } void Binder::IdentifierAnalysis() @@ -98,11 +140,10 @@ void Binder::IdentifierAnalysis() ASSERT(scope_ == topScope_); ASSERT(varScope_ == topScope_); - if (program_->Extension() == ScriptExtension::AS) { - return; - } + functionScopes_.push_back(topScope_); + topScope_->BindName(MAIN); + topScope_->BindInternalName(BuildFunctionName(MAIN, 0)); - BuildFunction(topScope_, "main"); topScope_->CheckDirectEval(compilerCtx_); ResolveReferences(program_->Ast()); @@ -150,7 +191,7 @@ void Binder::InstantiateArguments() scope->Bindings().insert({argumentsVariable->Name(), argumentsVariable}); } - scope->AsVariableScope()->AddFlag(VariableScopeFlags::USE_ARGS); + scope->AddFlag(ScopeFlags::USE_ARGS); break; } @@ -167,7 +208,7 @@ void Binder::PropagateDirectEval() const VariableScope *scope = iter->IsFunctionParamScope() ? iter->AsFunctionParamScope()->GetFunctionScope() : iter->EnclosingVariableScope(); - scope->AddFlag(VariableScopeFlags::NO_REG_STORE); + scope->AddFlag(ScopeFlags::NO_REG_STORE); iter = iter->Parent(); } while (iter != nullptr); } @@ -197,16 +238,20 @@ void Binder::InstantiatePrivateContext(const ir::Identifier *ident) const void Binder::LookupIdentReference(ir::Identifier *ident) { + if (!ident->IsReference()) { + return; + } + if (ident->Name().Is(FUNCTION_ARGUMENTS)) { InstantiateArguments(); } - if (ident->IsPrivate()) { + if (ident->IsPrivateIdent()) { InstantiatePrivateContext(ident); return; } - ScopeFindResult res = scope_->Find(ident->Name(), bindingOptions_); + ScopeFindResult res = scope_->Find(ident->Name(), BindingOptions()); if (res.level != 0) { ASSERT(res.variable); res.variable->SetLexical(res.scope); @@ -223,32 +268,29 @@ void Binder::LookupIdentReference(ir::Identifier *ident) ident->SetVariable(res.variable); } -void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name) +util::StringView Binder::BuildFunctionName(util::StringView name, uint32_t idx) { - uint32_t idx = functionScopes_.size(); - functionScopes_.push_back(funcScope); - std::stringstream ss; ss << "func_" << name << "_" << std::to_string(idx); util::UString internalName(ss.str(), Allocator()); - funcScope->BindName(name, internalName.View()); + return internalName.View(); } -void Binder::BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc) +bool Binder::BuildInternalName(const ir::ScriptFunction *scriptFunc) { - if (scriptFunc->IsArrow()) { - VariableScope *outerVarScope = outerScope->EnclosingVariableScope(); - outerVarScope->AddFlag(VariableScopeFlags::INNER_ARROW); - } + auto *funcScope = scriptFunc->Scope(); + auto name = util::Helpers::FunctionName(Allocator(), scriptFunc); - BuildFunction(scope_->AsFunctionScope(), util::Helpers::FunctionName(Allocator(), scriptFunc)); + uint32_t idx = functionScopes_.size(); + funcScope->BindName(name); + funcScope->BindInternalName(BuildFunctionName(name, idx)); + + return !scriptFunc->IsOverload(); } -void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode) +void Binder::BuildVarDeclaratorId(ir::AstNode *childNode) { - childNode->SetParent(parent); - switch (childNode->Type()) { case ir::AstNodeType::IDENTIFIER: { auto *ident = childNode->AsIdentifier(); @@ -259,12 +301,8 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN } auto *variable = scope_->FindLocal(name); - - if (Program()->Extension() == ScriptExtension::TS) { - ident->SetVariable(variable); - BuildTSSignatureDeclarationBaseParams(ident->TypeAnnotation()); - } - + ident->SetVariable(variable); + BuildSignatureDeclarationBaseParams(ident->TypeAnnotation()); variable->AddFlag(VariableFlags::INITIALIZED); break; } @@ -272,34 +310,34 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN auto *objPattern = childNode->AsObjectPattern(); for (auto *prop : objPattern->Properties()) { - BuildVarDeclaratorId(childNode, prop); + BuildVarDeclaratorId(prop); } - BuildTSSignatureDeclarationBaseParams(objPattern->TypeAnnotation()); + BuildSignatureDeclarationBaseParams(objPattern->TypeAnnotation()); break; } case ir::AstNodeType::ARRAY_PATTERN: { auto *arrayPattern = childNode->AsArrayPattern(); for (auto *element : childNode->AsArrayPattern()->Elements()) { - BuildVarDeclaratorId(childNode, element); + BuildVarDeclaratorId(element); } - BuildTSSignatureDeclarationBaseParams(arrayPattern->TypeAnnotation()); + BuildSignatureDeclarationBaseParams(arrayPattern->TypeAnnotation()); break; } case ir::AstNodeType::ASSIGNMENT_PATTERN: { - ResolveReference(childNode, childNode->AsAssignmentPattern()->Right()); - BuildVarDeclaratorId(childNode, childNode->AsAssignmentPattern()->Left()); + ResolveReference(childNode->AsAssignmentPattern()->Right()); + BuildVarDeclaratorId(childNode->AsAssignmentPattern()->Left()); break; } case ir::AstNodeType::PROPERTY: { - ResolveReference(childNode, childNode->AsProperty()->Key()); - BuildVarDeclaratorId(childNode, childNode->AsProperty()->Value()); + ResolveReference(childNode->AsProperty()->Key()); + BuildVarDeclaratorId(childNode->AsProperty()->Value()); break; } case ir::AstNodeType::REST_ELEMENT: { - BuildVarDeclaratorId(childNode, childNode->AsRestElement()->Argument()); + BuildVarDeclaratorId(childNode->AsRestElement()->Argument()); break; } default: @@ -307,86 +345,67 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN } } -void Binder::BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode) +void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) { - if (typeNode == nullptr) { + if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) { + ResolveReferences(varDecl); return; } - Scope *scope = nullptr; - - switch (typeNode->Type()) { - case ir::AstNodeType::TS_FUNCTION_TYPE: { - scope = typeNode->AsTSFunctionType()->Scope(); - break; - } - case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: { - scope = typeNode->AsTSConstructorType()->Scope(); - break; - } - case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { - scope = typeNode->AsTSSignatureDeclaration()->Scope(); - break; - } - case ir::AstNodeType::TS_METHOD_SIGNATURE: { - scope = typeNode->AsTSMethodSignature()->Scope(); - break; - } - default: { - ResolveReferences(typeNode); - return; - } + if (varDecl->Init()) { + ResolveReference(varDecl->Init()); } - ASSERT(scope && scope->IsFunctionParamScope()); + BuildVarDeclaratorId(varDecl->Id()); +} + +void Binder::BuildClassProperty(const ir::ClassProperty *prop) +{ + const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(prop); + auto scopeCtx = LexicalScope::Enter(this, ctor->Scope()); - auto scopeCtx = LexicalScope::Enter(this, scope->AsFunctionParamScope()); - ResolveReferences(typeNode); + ResolveReferences(prop); } -void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) +void Binder::InitializeClassBinding(ir::ClassDefinition *classDef) { - if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) { - ResolveReferences(varDecl); - return; - } + ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - if (varDecl->Init() != nullptr) { - ResolveReference(varDecl, varDecl->Init()); - } + ASSERT(res.variable && res.variable->Declaration()->IsLetDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); +} + +void Binder::InitializeClassIdent(ir::ClassDefinition *classDef) +{ + ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - BuildVarDeclaratorId(varDecl, varDecl->Id()); + ASSERT(res.variable && res.variable->Declaration()->IsConstDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); } void Binder::BuildClassDefinition(ir::ClassDefinition *classDef) { if (classDef->Parent()->IsClassDeclaration()) { - ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - - ASSERT(res.variable && res.variable->Declaration()->IsLetDecl()); - res.variable->AddFlag(VariableFlags::INITIALIZED); + InitializeClassBinding(classDef); } auto scopeCtx = LexicalScope::Enter(this, classDef->Scope()); if (classDef->Super() != nullptr) { - ResolveReference(classDef, classDef->Super()); + ResolveReference(classDef->Super()); } Variable *variable = scope_->FindLocal(classDef->PrivateId()); variable->AddFlag(VariableFlags::INITIALIZED); if (classDef->Ident() != nullptr) { - ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - - ASSERT(res.variable && res.variable->Declaration()->IsConstDecl()); - res.variable->AddFlag(VariableFlags::INITIALIZED); + InitializeClassIdent(classDef); } - ResolveReference(classDef, classDef->Ctor()); + ResolveReference(classDef->Ctor()); for (auto *stmt : classDef->Body()) { - ResolveReference(classDef, stmt); + ResolveReference(stmt); } } @@ -397,35 +416,35 @@ void Binder::BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt) auto declScopeCtx = LexicalScope::Enter(this, loopScope->DeclScope()); if (forUpdateStmt->Init() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Init()); + ResolveReference(forUpdateStmt->Init()); } if (forUpdateStmt->Update() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Update()); + ResolveReference(forUpdateStmt->Update()); } auto loopCtx = LexicalScope::Enter(this, loopScope); if (forUpdateStmt->Test() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Test()); + ResolveReference(forUpdateStmt->Test()); } - ResolveReference(forUpdateStmt, forUpdateStmt->Body()); + ResolveReference(forUpdateStmt->Body()); loopCtx.GetScope()->ConvertToVariableScope(Allocator()); } -void Binder::BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left, - ir::Expression *right, ir::Statement *body) +void Binder::BuildForInOfLoop(binder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right, + ir::Statement *body) { auto declScopeCtx = LexicalScope::Enter(this, loopScope->DeclScope()); - ResolveReference(parent, right); - ResolveReference(parent, left); + ResolveReference(right); + ResolveReference(left); auto loopCtx = LexicalScope::Enter(this, loopScope); - ResolveReference(parent, body); + ResolveReference(body); loopCtx.GetScope()->ConvertToVariableScope(Allocator()); } @@ -433,81 +452,98 @@ void Binder::BuildCatchClause(ir::CatchClause *catchClauseStmt) { if (catchClauseStmt->Param() != nullptr) { auto paramScopeCtx = LexicalScope::Enter(this, catchClauseStmt->Scope()->ParamScope()); - ResolveReference(catchClauseStmt, catchClauseStmt->Param()); + ResolveReference(catchClauseStmt->Param()); } auto scopeCtx = LexicalScope::Enter(this, catchClauseStmt->Scope()); - ResolveReference(catchClauseStmt, catchClauseStmt->Body()); + ResolveReference(catchClauseStmt->Body()); +} + +void Binder::AddCompilableFunction(ir::ScriptFunction *func) +{ + if (func->IsArrow()) { + VariableScope *outerVarScope = scope_->EnclosingVariableScope(); + outerVarScope->AddFlag(ScopeFlags::INNER_ARROW); + } + + AddCompilableFunctionScope(func->Scope()); +} + +void Binder::AddCompilableFunctionScope(binder::FunctionScope *funcScope) +{ + functionScopes_.push_back(funcScope); } -void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) +void Binder::VisitScriptFunction(ir::ScriptFunction *func) { - childNode->SetParent(parent); + auto *funcScope = func->Scope(); + { + auto paramScopeCtx = LexicalScope::Enter(this, funcScope->ParamScope()); + + for (auto *param : func->Params()) { + ResolveReference(param); + } + } + + if (func->ReturnTypeAnnotation()) { + ResolveReference(func->ReturnTypeAnnotation()); + } + + if (!BuildInternalName(func)) { + return; + } + + AddCompilableFunction(func); + + auto scopeCtx = LexicalScope::Enter(this, funcScope); + + if (func->Body()) { + ResolveReference(func->Body()); + } +} + +void Binder::VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func) +{ + if (func->TypeParams()) { + auto typeParamScopeCtx = LexicalScope::Enter(this, func->TypeParams()->Scope()); + VisitScriptFunction(func); + return; + } + + VisitScriptFunction(func); +} + +void Binder::ResolveReference(ir::AstNode *childNode) +{ switch (childNode->Type()) { case ir::AstNodeType::IDENTIFIER: { auto *ident = childNode->AsIdentifier(); - if (ident->IsReference()) { - LookupIdentReference(ident); - } - + LookupIdentReference(ident); ResolveReferences(childNode); break; } case ir::AstNodeType::SUPER_EXPRESSION: { VariableScope *varScope = scope_->EnclosingVariableScope(); - varScope->AddFlag(VariableScopeFlags::USE_SUPER); - + varScope->AddFlag(ScopeFlags::USE_SUPER); ResolveReferences(childNode); break; } case ir::AstNodeType::SCRIPT_FUNCTION: { - auto *scriptFunc = childNode->AsScriptFunction(); - auto *funcScope = scriptFunc->Scope(); - - auto *outerScope = scope_; - - { - auto paramScopeCtx = LexicalScope::Enter(this, funcScope->ParamScope()); - - for (auto *param : scriptFunc->Params()) { - ResolveReference(scriptFunc, param); - } - } - - if (Program()->Extension() == ScriptExtension::TS) { - if (scriptFunc->ReturnTypeAnnotation() != nullptr) { - ResolveReference(scriptFunc, scriptFunc->ReturnTypeAnnotation()); - } - - if (scriptFunc->IsOverload()) { - break; - } - } - - auto scopeCtx = LexicalScope::Enter(this, funcScope); - - BuildScriptFunction(outerScope, scriptFunc); - - ResolveReference(scriptFunc, scriptFunc->Body()); + VisitScriptFunctionWithPotentialTypeParams(childNode->AsScriptFunction()); break; } case ir::AstNodeType::VARIABLE_DECLARATOR: { BuildVarDeclarator(childNode->AsVariableDeclarator()); - break; } case ir::AstNodeType::CLASS_DEFINITION: { BuildClassDefinition(childNode->AsClassDefinition()); - break; } case ir::AstNodeType::CLASS_PROPERTY: { - const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(childNode->AsClassProperty()); - auto scopeCtx = LexicalScope::Enter(this, ctor->Scope()); - - ResolveReferences(childNode); + BuildClassProperty(childNode->AsClassProperty()); break; } case ir::AstNodeType::BLOCK_STATEMENT: { @@ -527,18 +563,18 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) { auto loopScopeCtx = LexicalScope::Enter(this, doWhileStatement->Scope()); - ResolveReference(doWhileStatement, doWhileStatement->Body()); + ResolveReference(doWhileStatement->Body()); } - ResolveReference(doWhileStatement, doWhileStatement->Test()); + ResolveReference(doWhileStatement->Test()); break; } case ir::AstNodeType::WHILE_STATEMENT: { auto *whileStatement = childNode->AsWhileStatement(); - ResolveReference(whileStatement, whileStatement->Test()); + ResolveReference(whileStatement->Test()); auto loopScopeCtx = LexicalScope::Enter(this, whileStatement->Scope()); - ResolveReference(whileStatement, whileStatement->Body()); + ResolveReference(whileStatement->Body()); break; } @@ -548,36 +584,29 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) } case ir::AstNodeType::FOR_IN_STATEMENT: { auto *forInStmt = childNode->AsForInStatement(); - BuildForInOfLoop(forInStmt, forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body()); + BuildForInOfLoop(forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body()); break; } case ir::AstNodeType::FOR_OF_STATEMENT: { auto *forOfStmt = childNode->AsForOfStatement(); - BuildForInOfLoop(forOfStmt, forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body()); + BuildForInOfLoop(forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body()); break; } case ir::AstNodeType::CATCH_CLAUSE: { BuildCatchClause(childNode->AsCatchClause()); break; } - // TypeScript specific part - case ir::AstNodeType::TS_FUNCTION_TYPE: - case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: - case ir::AstNodeType::TS_METHOD_SIGNATURE: - case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { - BuildTSSignatureDeclarationBaseParams(childNode); - break; - } default: { - ResolveReferences(childNode); + HandleCustomNodes(childNode); break; } } } + void Binder::ResolveReferences(const ir::AstNode *parent) { - parent->Iterate([this, parent](auto *childNode) { ResolveReference(parent, childNode); }); + parent->Iterate([this](auto *childNode) { ResolveReference(childNode); }); } LocalVariable *Binder::AddMandatoryParam(const std::string_view &name) @@ -601,7 +630,7 @@ void Binder::LookUpMandatoryReferences(const FunctionScope *funcScope, bool need LookupReference(MANDATORY_PARAM_NEW_TARGET); LookupReference(MANDATORY_PARAM_THIS); - if (funcScope->HasFlag(VariableScopeFlags::USE_ARGS)) { + if (funcScope->HasFlag(ScopeFlags::USE_ARGS)) { LookupReference(FUNCTION_ARGUMENTS); } @@ -649,9 +678,9 @@ void Binder::AddMandatoryParams() bool lexicalFunctionObject {}; if (ctor != nullptr && util::Helpers::GetClassDefiniton(ctor)->Super() != nullptr && - funcScope->HasFlag(VariableScopeFlags::USE_SUPER)) { - ASSERT(ctor->Scope()->HasFlag(VariableScopeFlags::INNER_ARROW)); - ctor->Scope()->AddFlag(VariableScopeFlags::SET_LEXICAL_FUNCTION); + funcScope->HasFlag(ScopeFlags::USE_SUPER)) { + ASSERT(ctor->Scope()->HasFlag(ScopeFlags::INNER_ARROW)); + ctor->Scope()->AddFlag(ScopeFlags::SET_LEXICAL_FUNCTION); lexicalFunctionObject = true; AddMandatoryParams(CTOR_ARROW_MANDATORY_PARAMS); } else { diff --git a/binder/binder.h b/binder/binder.h index 2f67336d1..33d5dc9fb 100644 --- a/binder/binder.h +++ b/binder/binder.h @@ -20,7 +20,11 @@ #include "plugins/ecmascript/es2panda/binder/variableFlags.h" #include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" #include "macros.h" -#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::parser { +class Program; +enum class ScriptKind; +} // namespace panda::es2panda::parser namespace panda::es2panda::ir { class AstNode; @@ -34,28 +38,22 @@ class ScriptFunction; class Statement; class VariableDeclarator; class TSFunctionType; +class ThisExpression; +class MemberExpression; +class ClassStaticBlock; } // namespace panda::es2panda::ir namespace panda::es2panda::binder { class Binder { public: - explicit Binder(parser::Program *program, ScriptExtension extension) - : program_(program), functionScopes_(Allocator()->Adapter()) - { - if (extension == ScriptExtension::TS) { - bindingOptions_ = ResolveBindingOptions::ALL; - return; - } - - bindingOptions_ = ResolveBindingOptions::BINDINGS; - } + explicit Binder(ArenaAllocator *allocator) : allocator_(allocator), functionScopes_(allocator_->Adapter()) {} NO_COPY_SEMANTIC(Binder); - DEFAULT_MOVE_SEMANTIC(Binder); + NO_MOVE_SEMANTIC(Binder); ~Binder() = default; void InitTopScope(); - void IdentifierAnalysis(); + virtual void IdentifierAnalysis(); template T *AddDecl(const lexer::SourcePosition &pos, Args &&...args); @@ -63,7 +61,25 @@ public: template T *AddTsDecl(const lexer::SourcePosition &pos, Args &&...args); - ParameterDecl *AddParamDecl(const ir::AstNode *param); + ParameterDecl *AddParamDecl(ir::AstNode *param); + + void SetProgram(parser::Program *program) + { + ASSERT(!program_); + program_ = program; + } + + parser::Program *Program() + { + ASSERT(program_); + return program_; + } + + const parser::Program *Program() const + { + ASSERT(program_); + return program_; + } void SetCompilerContext(compiler::CompilerContext *compilerContext) { @@ -82,12 +98,26 @@ public: return scope_; } + void ResetTopScope(GlobalScope *topScope) + { + ASSERT(topScope_ == scope_); + topScope_ = topScope; + varScope_ = topScope_; + scope_ = topScope_; + } + GlobalScope *TopScope() const { return topScope_; } - [[noreturn]] void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name); + [[noreturn]] void ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowUnresolvableVariable(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowError(const lexer::SourcePosition &pos, const std::string_view &name) const; void PropagateDirectEval() const; @@ -96,7 +126,7 @@ public: inline ArenaAllocator *Allocator() const { - return program_->Allocator(); + return allocator_; } const ArenaVector &Functions() const @@ -109,9 +139,14 @@ public: return functionScopes_; } - const parser::Program *Program() const + virtual ScriptExtension Extension() const { - return program_; + return ScriptExtension::JS; + } + + virtual ResolveBindingOptions BindingOptions() const + { + return ResolveBindingOptions::BINDINGS; } static constexpr std::string_view FUNCTION_ARGUMENTS = "arguments"; @@ -127,9 +162,11 @@ public: static constexpr std::string_view LEXICAL_MANDATORY_PARAM_THIS = "!t"; static constexpr std::string_view LEXICAL_CONTEXT_PARAM = "=eval"; + static constexpr std::string_view MAIN = "main"; static constexpr uint32_t LEXICAL_CONTEXT_PARAM_REG = MANDATORY_PARAMS_NUMBER; + static constexpr std::string_view STAR_IMPORT = "*"; -private: +protected: template using MandatoryParams = std::array; @@ -150,27 +187,38 @@ private: template void AddMandatoryParams(const MandatoryParams ¶ms); void AddMandatoryParams(); - void BuildFunction(FunctionScope *funcScope, util::StringView name); - void BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc); - void BuildClassDefinition(ir::ClassDefinition *classDef); void LookupReference(const util::StringView &name); void InstantiateArguments(); void InstantiatePrivateContext(const ir::Identifier *ident) const; void BuildVarDeclarator(ir::VariableDeclarator *varDecl); - void BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode); + void BuildVarDeclaratorId(ir::AstNode *childNode); void BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt); - void BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left, - ir::Expression *right, ir::Statement *body); + void BuildForInOfLoop(binder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right, ir::Statement *body); void BuildCatchClause(ir::CatchClause *catchClauseStmt); - void LookupIdentReference(ir::Identifier *ident); - void ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode); + void ResolveReference(ir::AstNode *childNode); void ResolveReferences(const ir::AstNode *parent); + void VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func); + void VisitScriptFunction(ir::ScriptFunction *func); + util::StringView BuildFunctionName(util::StringView name, uint32_t idx); - // TypeScript specific functions - void BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode); - [[noreturn]] void ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const; + void AddCompilableFunction(ir::ScriptFunction *func); + void AddCompilableFunctionScope(binder::FunctionScope *funcScope); + + void InitializeClassBinding(ir::ClassDefinition *classDef); + void InitializeClassIdent(ir::ClassDefinition *classDef); + + virtual void LookupIdentReference(ir::Identifier *ident); + virtual void HandleCustomNodes(ir::AstNode *childNode) + { + ResolveReferences(childNode); + } + virtual void BuildSignatureDeclarationBaseParams([[maybe_unused]] const ir::AstNode *typeNode) {}; + virtual void BuildClassDefinition(ir::ClassDefinition *classDef); + virtual void BuildClassProperty(const ir::ClassProperty *prop); + virtual bool BuildInternalName(const ir::ScriptFunction *scriptFunc); parser::Program *program_ {}; + ArenaAllocator *allocator_ {}; compiler::CompilerContext *compilerCtx_ {}; GlobalScope *topScope_ {}; Scope *scope_ {}; @@ -201,10 +249,10 @@ public: binder_->varScope_ = prevVarScope_; } - [[nodiscard]] static LexicalScope Enter(Binder *binder, T *scope) + [[nodiscard]] static LexicalScope Enter(Binder *binder, T *scope, bool checkEval = true) { LexicalScope lexScope(scope, binder); - if (binder->Program()->Extension() == ScriptExtension::TS) { + if (!checkEval || binder->Extension() == ScriptExtension::TS) { return lexScope; } // NOLINTNEXTLINE(readability-braces-around-statements) @@ -266,7 +314,7 @@ T *Binder::AddTsDecl(const lexer::SourcePosition &pos, Args &&...args) { T *decl = Allocator()->New(std::forward(args)...); - if (scope_->AddTsDecl(Allocator(), decl, program_->Extension())) { + if (scope_->AddTsDecl(Allocator(), decl, Extension())) { return decl; } @@ -278,7 +326,7 @@ T *Binder::AddDecl(const lexer::SourcePosition &pos, Args &&...args) { T *decl = Allocator()->New(std::forward(args)...); - if (scope_->AddDecl(Allocator(), decl, program_->Extension())) { + if (scope_->AddDecl(Allocator(), decl, Extension())) { return decl; } diff --git a/binder/declaration.h b/binder/declaration.h index ba4cee19e..e2c09a3d2 100644 --- a/binder/declaration.h +++ b/binder/declaration.h @@ -49,6 +49,11 @@ public: return name_; } + ir::AstNode *Node() + { + return node_; + } + const ir::AstNode *Node() const { return node_; @@ -73,7 +78,7 @@ public: DECLARATION_KINDS(DECLARE_CHECKS_CASTS) #undef DECLARE_CHECKS_CASTS - void BindNode(const ir::AstNode *node) + void BindNode(ir::AstNode *node) { node_ = node; } @@ -83,12 +88,17 @@ public: return IsLetDecl() || IsConstDecl(); } + bool PossibleTDZ() const + { + return IsLetOrConstDecl() || IsParameterDecl(); + } + protected: explicit Decl(util::StringView name) : name_(name) {} // NOLINTBEGIN(misc-non-private-member-variables-in-classes) util::StringView name_; - const ir::AstNode *node_ {}; + ir::AstNode *node_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) }; @@ -153,9 +163,19 @@ public: } }; +class ClassDecl : public Decl { +public: + explicit ClassDecl(util::StringView name) : Decl(name) {} + + DeclType Type() const override + { + return DeclType::CLASS; + } +}; + class FunctionDecl : public MultiDecl { public: - explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, const ir::AstNode *node) + explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, ir::AstNode *node) : MultiDecl(allocator, name) { node_ = node; @@ -169,7 +189,7 @@ public: class TypeParameterDecl : public Decl { public: - explicit TypeParameterDecl(util::StringView name, const ir::AstNode *node); + explicit TypeParameterDecl(util::StringView name) : Decl(name) {} DeclType Type() const override { @@ -274,7 +294,7 @@ public: { } - explicit ImportDecl(util::StringView importName, util::StringView localName, const ir::AstNode *node) + explicit ImportDecl(util::StringView importName, util::StringView localName, ir::AstNode *node) : Decl(localName), importName_(importName) { BindNode(node); @@ -306,7 +326,7 @@ public: { } - explicit ExportDecl(util::StringView exportName, util::StringView localName, const ir::AstNode *node) + explicit ExportDecl(util::StringView exportName, util::StringView localName, ir::AstNode *node) : Decl(localName), exportName_(exportName) { BindNode(node); diff --git a/binder/recordTable.cpp b/binder/recordTable.cpp new file mode 100644 index 000000000..4ee982d7b --- /dev/null +++ b/binder/recordTable.cpp @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "recordTable.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "generated/signatures.h" + +namespace panda::es2panda::binder { + +BoundContext::BoundContext(RecordTable *recordTable, ir::ClassDefinition *classDef) + : prev_(recordTable->boundCtx_), + recordTable_(recordTable), + savedClassDefinition_(recordTable->classDefinition_), + savedInterfaceDeclaration_(recordTable->interfaceDeclaration_) +{ + if (!classDef || !recordTable_->classDefinitions_.insert(classDef).second) { + return; + } + + recordTable_->boundCtx_ = this; + recordTable_->classDefinition_ = classDef; + recordTable_->interfaceDeclaration_ = nullptr; + recordIdent_ = classDef->Ident(); + classDef->SetInternalName(FormRecordName()); +} + +BoundContext::BoundContext(RecordTable *recordTable, ir::TSInterfaceDeclaration *interfaceDecl) + : prev_(recordTable->boundCtx_), + recordTable_(recordTable), + savedClassDefinition_(recordTable->classDefinition_), + savedInterfaceDeclaration_(recordTable->interfaceDeclaration_) +{ + if (!interfaceDecl || !recordTable_->interfaceDeclarations_.insert(interfaceDecl).second) { + return; + } + + recordTable_->boundCtx_ = this; + recordTable_->classDefinition_ = nullptr; + recordTable_->interfaceDeclaration_ = interfaceDecl; + recordIdent_ = interfaceDecl->Id(); + interfaceDecl->SetInternalName(FormRecordName()); +} + +BoundContext::~BoundContext() +{ + recordTable_->classDefinition_ = savedClassDefinition_; + recordTable_->interfaceDeclaration_ = savedInterfaceDeclaration_; + recordTable_->boundCtx_ = prev_; +} + +util::StringView BoundContext::FormRecordName() const +{ + auto packageName = recordTable_->program_->GetPackageName(); + if (prev_ == nullptr && packageName.Empty()) { + return recordIdent_->Name(); + } + + util::UString recordName(recordTable_->program_->Allocator()); + if (prev_ == nullptr && !packageName.Empty()) { + recordName.Append(packageName); + recordName.Append(compiler::Signatures::METHOD_SEPARATOR); + recordName.Append(recordIdent_->Name()); + return recordName.View(); + } + + recordName.Append(prev_->FormRecordName()); + recordName.Append(compiler::Signatures::METHOD_SEPARATOR); + recordName.Append(recordIdent_->Name()); + return recordName.View(); +} + +util::StringView RecordTable::RecordName() const +{ + if (classDefinition_) { + return classDefinition_->InternalName(); + } + + return interfaceDeclaration_->Id()->Name(); +} + +} // namespace panda::es2panda::binder diff --git a/binder/recordTable.h b/binder/recordTable.h new file mode 100644 index 000000000..986679db0 --- /dev/null +++ b/binder/recordTable.h @@ -0,0 +1,184 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_recordTable_RECORD_TABLE_H +#define ES2PANDA_recordTable_RECORD_TABLE_H + +#include "macros.h" +#include "utils/arena_containers.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +namespace panda::es2panda::parser { +class Program; +} // namespace panda::es2panda::parser + +namespace panda::es2panda::checker { +class Signature; +} // namespace panda::es2panda::checker + +namespace panda::es2panda::ir { +class ClassDefinition; +class TSInterfaceDeclaration; +class Identifier; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { +class FunctionScope; +class BoundContext; + +enum class RecordTableFlags { + NONE = 0, + EXTERNAL = 1 << 0, +}; + +DEFINE_BITOPS(RecordTableFlags) + +class RecordTable { +public: + explicit RecordTable(ArenaAllocator *allocator, parser::Program *program, RecordTableFlags flags) + : classDefinitions_(allocator->Adapter()), + interfaceDeclarations_(allocator->Adapter()), + signatures_(allocator->Adapter()), + program_(program), + flags_(flags) + { + } + + NO_COPY_SEMANTIC(RecordTable); + NO_MOVE_SEMANTIC(RecordTable); + + ~RecordTable() = default; + + bool IsExternal() const + { + return (flags_ & RecordTableFlags::EXTERNAL) != 0; + } + + ArenaUnorderedSet &ClassDefinitions() + { + return classDefinitions_; + } + + const ArenaUnorderedSet &ClassDefinitions() const + { + return classDefinitions_; + } + + ArenaUnorderedSet &InterfaceDeclarations() + { + return interfaceDeclarations_; + } + + const ArenaUnorderedSet &InterfaceDeclarations() const + { + return interfaceDeclarations_; + } + + ArenaVector &Signatures() + { + return signatures_; + } + + const ArenaVector &Signatures() const + { + return signatures_; + } + + void SetClassDefinition(ir::ClassDefinition *classDefinition) + { + classDefinition_ = classDefinition; + } + + ir::ClassDefinition *ClassDefinition() + { + return classDefinition_; + } + + const ir::ClassDefinition *ClassDefinition() const + { + return classDefinition_; + } + + void SetInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDeclaration) + { + interfaceDeclaration_ = interfaceDeclaration; + } + + ir::TSInterfaceDeclaration *InterfaceDeclaration() + { + return interfaceDeclaration_; + } + + const ir::TSInterfaceDeclaration *InterfaceDeclaration() const + { + return interfaceDeclaration_; + } + + void SetProgram(parser::Program *program) + { + program_ = program; + } + + parser::Program *Program() + { + return program_; + } + + const parser::Program *Program() const + { + return program_; + } + + util::StringView RecordName() const; + +private: + friend class BoundContext; + + ArenaUnorderedSet classDefinitions_; + ArenaUnorderedSet interfaceDeclarations_; + ArenaVector signatures_; + ir::ClassDefinition *classDefinition_ {}; + ir::TSInterfaceDeclaration *interfaceDeclaration_ {}; + parser::Program *program_ {}; + BoundContext *boundCtx_ {}; + RecordTableFlags flags_ {}; +}; + +class BoundContext { +public: + explicit BoundContext(RecordTable *recordTable, ir::ClassDefinition *classDef); + explicit BoundContext(RecordTable *recordTable, ir::TSInterfaceDeclaration *interfaceDecl); + ~BoundContext(); + + NO_COPY_SEMANTIC(BoundContext); + NO_MOVE_SEMANTIC(BoundContext); + + void *operator new(size_t) = delete; + void *operator new[](size_t) = delete; + + util::StringView FormRecordName() const; + +private: + BoundContext *prev_; + RecordTable *recordTable_; + ir::ClassDefinition *savedClassDefinition_ {}; + ir::TSInterfaceDeclaration *savedInterfaceDeclaration_ {}; + ir::Identifier *recordIdent_; +}; + +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/scope.cpp b/binder/scope.cpp index 2c8fbad99..0287fd67b 100644 --- a/binder/scope.cpp +++ b/binder/scope.cpp @@ -200,6 +200,10 @@ bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::INTERFACE)}); return true; } + case DeclType::TYPE_PARAMETER: { + bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::TYPE_PARAMETER)}); + return true; + } case DeclType::FUNC: { flags = VariableFlags::HOIST; [[fallthrough]]; @@ -227,7 +231,7 @@ void VariableScope::CheckDirectEval(compiler::CompilerContext *compilerCtx) { ASSERT(compilerCtx); - if (!HasFlag(VariableScopeFlags::NO_REG_STORE) || bindings_.empty()) { + if (!HasFlag(ScopeFlags::NO_REG_STORE) || bindings_.empty()) { evalBindings_ = compiler::INVALID_LITERAL_BUFFER_ID; return; } @@ -291,8 +295,7 @@ bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, return true; } -std::tuple ParamScope::AddParamDecl(ArenaAllocator *allocator, - const ir::AstNode *param) +std::tuple ParamScope::AddParamDecl(ArenaAllocator *allocator, ir::AstNode *param) { const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size()); @@ -307,9 +310,9 @@ std::tuple ParamScope::AddParamDecl(ArenaA return {decl, nullptr}; } - std::vector bindings = util::Helpers::CollectBindingNames(param); + std::vector bindings = util::Helpers::CollectBindingNames(param); - for (const auto *binding : bindings) { + for (auto *binding : bindings) { auto *varDecl = NewDecl(allocator, binding->Name()); varDecl->BindNode(binding); @@ -427,7 +430,7 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl } } -void ModuleScope::AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls) +void ModuleScope::AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls) { auto res = imports_.emplace_back(importDecl, decls); @@ -436,7 +439,7 @@ void ModuleScope::AddImportDecl(const ir::ImportDeclaration *importDecl, ImportD } } -void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl) +void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl) { decl->BindNode(exportDecl); @@ -446,7 +449,7 @@ void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl) AddExportDecl(exportDecl, std::move(decls)); } -void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls) +void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls) { auto res = exports_.emplace_back(exportDecl, decls); diff --git a/binder/scope.h b/binder/scope.h index 9beb2fcc0..07f6d8fb8 100644 --- a/binder/scope.h +++ b/binder/scope.h @@ -18,7 +18,7 @@ #include "plugins/ecmascript/es2panda/binder/declaration.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/es2panda.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" #include "plugins/ecmascript/es2panda/util/ustring.h" @@ -127,6 +127,21 @@ public: const VariableScope *EnclosingVariableScope() const; + void AddFlag(ScopeFlags flag) + { + flags_ |= flag; + } + + void ClearFlag(ScopeFlags flag) + { + flags_ &= ~flag; + } + + bool HasFlag(ScopeFlags flag) const + { + return (flags_ & flag) != 0; + } + const ArenaVector &Decls() const { return decls_; @@ -162,12 +177,17 @@ public: endIns_ = ins; } + ir::AstNode *Node() + { + return node_; + } + const ir::AstNode *Node() const { return node_; } - void BindNode(const ir::AstNode *node) + void BindNode(ir::AstNode *node) { node_ = node; } @@ -192,7 +212,7 @@ public: template static VariableType *CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, - const ir::AstNode *node); + ir::AstNode *node); template void PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args); @@ -243,7 +263,8 @@ protected: Scope *parent_ {}; ArenaVector decls_; VariableMap bindings_; - const ir::AstNode *node_ {}; + ir::AstNode *node_ {}; + ScopeFlags flags_ {}; const compiler::IRNode *startIns_ {}; const compiler::IRNode *endIns_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -255,21 +276,6 @@ public: NO_COPY_SEMANTIC(VariableScope); NO_MOVE_SEMANTIC(VariableScope); - void AddFlag(VariableScopeFlags flag) - { - flags_ |= flag; - } - - void ClearFlag(VariableScopeFlags flag) - { - flags_ &= ~flag; - } - - bool HasFlag(VariableScopeFlags flag) const - { - return (flags_ & flag) != 0; - } - uint32_t NextSlot() { return slotIndex_++; @@ -309,7 +315,6 @@ protected: bool AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - VariableScopeFlags flags_ {}; uint32_t evalBindings_ {}; uint32_t slotIndex_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -332,7 +337,7 @@ public: return params_; } - std::tuple AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param); + std::tuple AddParamDecl(ArenaAllocator *allocator, ir::AstNode *param); protected: explicit ParamScope(ArenaAllocator *allocator, Scope *parent) @@ -429,9 +434,13 @@ public: return ScopeType::FUNCTION; } - void BindName(util::StringView name, util::StringView internalName) + void BindName(util::StringView name) { name_ = name; + } + + void BindInternalName(util::StringView internalName) + { internalName_ = internalName; } @@ -604,12 +613,12 @@ public: return ScopeType::MODULE; } - const ModuleEntry &Imports() const + const ModuleEntry &Imports() const { return imports_; } - const ModuleEntry &Exports() const + const ModuleEntry &Exports() const { return exports_; } @@ -619,11 +628,11 @@ public: return localExports_; } - void AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls); + void AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls); - void AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl); + void AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl); - void AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls); + void AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls); bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) override; @@ -634,8 +643,8 @@ private: bool AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); ArenaAllocator *allocator_; - ModuleEntry imports_; - ModuleEntry exports_; + ModuleEntry imports_; + ModuleEntry exports_; LocalExportNameMap localExports_; }; @@ -739,8 +748,7 @@ VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, V } template -VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, - const ir::AstNode *node) +VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, ir::AstNode *node) { auto *decl = allocator->New(name); auto *variable = allocator->New(decl, flags); diff --git a/binder/variable.h b/binder/variable.h index ffa856132..e32c59ba7 100644 --- a/binder/variable.h +++ b/binder/variable.h @@ -65,7 +65,12 @@ public: VARIABLE_TYPES(DECLARE_CHECKS_CASTS) #undef DECLARE_CHECKS_CASTS - Decl *Declaration() const + const Decl *Declaration() const + { + return decl_; + } + + Decl *Declaration() { return decl_; } @@ -143,7 +148,7 @@ public: { ASSERT(!LexicalBound()); AddFlag(VariableFlags::LEXICAL_BOUND); - vreg_ = slot; + vreg_.SetIndex(slot); } compiler::VReg Vreg() const @@ -151,17 +156,22 @@ public: return vreg_; } + compiler::VReg &Vreg() + { + return vreg_; + } + uint32_t LexIdx() const { ASSERT(LexicalBound()); - return vreg_; + return vreg_.GetIndex(); } void SetLexical([[maybe_unused]] Scope *scope) override; LocalVariable *Copy(ArenaAllocator *allocator, Decl *decl) const; private: - uint32_t vreg_ {}; + compiler::VReg vreg_ {}; }; class GlobalVariable : public Variable { diff --git a/binder/variableFlags.h b/binder/variableFlags.h index 7be9b096f..39daef9f8 100644 --- a/binder/variableFlags.h +++ b/binder/variableFlags.h @@ -35,6 +35,7 @@ namespace panda::es2panda::binder { _(ENUM_LITERAL, EnumLiteralDecl) \ _(TYPE_PARAMETER, TypeParameterDecl) \ _(PROPERTY, PropertyDecl) \ + _(CLASS, ClassDecl) \ _(METHOD, MethodDecl) \ _(ENUM, EnumDecl) @@ -124,7 +125,16 @@ enum class VariableFlags : uint32_t { INITIALIZED = 0x80000U, LEXICAL_BOUND = 0x100000U, + TYPE_PARAMETER = 0x200000U, + STATIC = 0x400000U, + CLASS = 0x800000U, + EXPLICIT_INIT_REQUIRED = 0x1000000U, + PUBLIC = 0x2000000U, + PROTECTED = 0x4000000U, + PRIVATE = 0x8000000U, + HOIST_VAR = HOIST | VAR, + CLASS_OR_INTERFACE = CLASS | INTERFACE, }; DEFINE_BITOPS(VariableFlags) @@ -134,16 +144,17 @@ enum class LetOrConstStatus { UNINITIALIZED, }; -enum class VariableScopeFlags : uint32_t { +enum class ScopeFlags : uint32_t { NONE = 0x0U, SET_LEXICAL_FUNCTION = 0x1U, USE_ARGS = 0x2U, USE_SUPER = 0x4U, INNER_ARROW = 0x8U, NO_REG_STORE = 0x10U, + DEFER_STMT = 0x20U, }; -DEFINE_BITOPS(VariableScopeFlags) +DEFINE_BITOPS(ScopeFlags) } // namespace panda::es2panda::binder #endif diff --git a/checker/ASchecker.cpp b/checker/ASchecker.cpp new file mode 100644 index 000000000..221945cbb --- /dev/null +++ b/checker/ASchecker.cpp @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ASchecker.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool ASChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + + if (options.dumpAst) { + std::cout << program_->Dump() << std::endl; + } + + return false; +} + +} // namespace panda::es2panda::checker diff --git a/checker/ASchecker.h b/checker/ASchecker.h new file mode 100644 index 000000000..4f472e00f --- /dev/null +++ b/checker/ASchecker.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_CHECKER_AS_CHECKER_H +#define ES2PANDA_CHECKER_AS_CHECKER_H + +#include "plugins/ecmascript/es2panda/checker/checker.h" + +namespace panda::es2panda::checker { + +class ASChecker : public Checker { +public: + explicit ASChecker() : Checker() {} + + bool StartChecker([[maybe_unused]] binder::Binder *binder, + [[maybe_unused]] const CompilerOptions &options) override; + Type *CheckTypeCached([[maybe_unused]] ir::Expression *expr) override + { + return nullptr; + } + + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} + + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override + { + return nullptr; + } +}; + +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/checker/JSchecker.cpp b/checker/JSchecker.cpp new file mode 100644 index 000000000..964a1b567 --- /dev/null +++ b/checker/JSchecker.cpp @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "JSchecker.h" + +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool JSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + binder->IdentifierAnalysis(); + + if (options.dumpAst) { + std::cout << program_->Dump() << std::endl; + } + + return !options.parseOnly; +} + +} // namespace panda::es2panda::checker diff --git a/checker/JSchecker.h b/checker/JSchecker.h new file mode 100644 index 000000000..14cad67db --- /dev/null +++ b/checker/JSchecker.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_CHECKER_JS_CHECKER_H +#define ES2PANDA_CHECKER_JS_CHECKER_H + +#include "plugins/ecmascript/es2panda/checker/checker.h" + +namespace panda::es2panda::checker { + +class JSChecker : public Checker { +public: + explicit JSChecker() : Checker() {} + + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; + + Type *CheckTypeCached([[maybe_unused]] ir::Expression *expr) override + { + return nullptr; + } + + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} + + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override + { + return nullptr; + } +}; + +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/checker/STSchecker.cpp b/checker/STSchecker.cpp new file mode 100644 index 000000000..c2e85bf28 --- /dev/null +++ b/checker/STSchecker.cpp @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "STSchecker.h" + +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/checker/sts/aliveAnalyzer.h" + +namespace panda::es2panda::checker { +bool STSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + + if (options.dumpAst) { + std::cout << program_->Dump() << std::endl; + } + + if (options.parseOnly) { + return false; + } + + binder->IdentifierAnalysis(); + + CheckProgram(program_, true); + + auto *stsBinder = static_cast(binder); + + for (auto *func : binder->Functions()) { + stsBinder->BuildFunctionName(func->Node()->AsScriptFunction()); + } + + return true; +} + +void STSChecker::CheckProgram(parser::Program *program, bool runAnalysis) +{ + auto *savedProgram = program_; + program_ = program; + + for (auto &[package, extPrograms] : program->ExternalSources()) { + for (auto *extProg : extPrograms) { + CheckProgram(extProg); + } + } + + ASSERT(program_->Ast()->IsProgram()); + program_->Ast()->Check(this); + + if (runAnalysis) { + AliveAnalyzer(program_->Ast(), this); + } + + auto *binder = static_cast(binder_); + auto *recordTable = binder->GetExternalRecordTable().find(program)->second; + + InitializeRecordElements(binder, recordTable); + + program_ = savedProgram; +} + +void STSChecker::InitializeRecordElements(binder::STSBinder *binder, binder::RecordTable *recordTable) +{ + for (auto *func : recordTable->Signatures()) { + binder->BuildFunctionName(func->Node()->AsScriptFunction()); + } +} + +Type *STSChecker::CheckTypeCached(ir::Expression *expr) +{ + if (!expr->TsType()) { + expr->SetTsType(expr->Check(this)); + } + + return expr->TsType(); +} +} // namespace panda::es2panda::checker diff --git a/checker/STSchecker.h b/checker/STSchecker.h new file mode 100644 index 000000000..8ed5f1720 --- /dev/null +++ b/checker/STSchecker.h @@ -0,0 +1,376 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_CHECKER_STS_CHECKER_H +#define ES2PANDA_CHECKER_STS_CHECKER_H + +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/sts/primitiveWrappers.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" + +#include "macros.h" + +#include +#include +#include +#include + +namespace panda::es2panda::binder { +class Binder; +class Decl; +class EnumVariable; +class FunctionDecl; +class LocalVariable; +class Scope; +class Variable; +class STSBinder; +class RecordTable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +enum class OperationType { + BITWISE_AND, + BITWISE_OR, + BITWISE_XOR, + LEFT_SHIFT, + RIGHT_SHIFT, + ADDITON, + SUBSTRACTION, + MULTIPLICATION, + DIVISION, + MOD, + LESS_THAN, + LESS_THAN_EQUAL, + GREATER_THAN, + GREATER_THAN_EQUAL, +}; + +enum class OverrideErrorCode { + NO_ERROR, + OVERRIDING_STATIC, + OVERRIDEN_STATIC, + OVERRIDEN_NOT_OPEN, + INCOMPATIBLE_RETURN, + OVERRIDEN_WEAKER, +}; + +using ComputedAbstracts = + ArenaUnorderedMap, std::unordered_set>>; +using ArrayMap = ArenaUnorderedMap; +using GlobalArraySignatureMap = ArenaUnorderedMap; + +class STSChecker : public Checker { +public: + explicit STSChecker() + : Checker(), + arrayTypes_(Allocator()->Adapter()), + globalArraySignatures_(Allocator()->Adapter()), + primitiveWrappers_(Allocator()), + cachedComputedAbstracts_(Allocator()->Adapter()) + { + } + + static inline TypeFlag STSType(const Type *type) + { + return static_cast(type->TypeFlags() & TypeFlag::STS_TYPE); + } + + static inline TypeFlag TypeKind(const Type *type) + { + return static_cast(type->TypeFlags() & checker::TypeFlag::STS_TYPE); + } + + Type *GlobalByteType() const + { + return globalTypes_->GlobalByteType(); + } + + Type *GlobalShortType() const + { + return globalTypes_->GlobalShortType(); + } + + Type *GlobalIntType() const + { + return globalTypes_->GlobalIntType(); + } + + Type *GlobalLongType() const + { + return globalTypes_->GlobalLongType(); + } + + Type *GlobalFloatType() const + { + return globalTypes_->GlobalFloatType(); + } + + Type *GlobalDoubleType() const + { + return globalTypes_->GlobalDoubleType(); + } + + Type *GlobalCharType() const + { + return globalTypes_->GlobalCharType(); + } + + Type *GlobalSTSBooleanType() const + { + return globalTypes_->GlobalSTSBooleanType(); + } + + Type *GlobalVoidType() const + { + return globalTypes_->GlobalSTSVoidType(); + } + + Type *GlobalSTSObjectType() const + { + return globalTypes_->GlobalSTSObjectType(); + } + + Type *GlobalSTSNullType() const + { + return globalTypes_->GlobalSTSNullType(); + } + + Type *GlobalSTSStringType() const + { + return globalTypes_->GlobalSTSStringType(); + } + + Type *GlobalWildcardType() const + { + return globalTypes_->GLobalWildcardType(); + } + + STSObjectType *GlobalBuiltinObjectType() + { + return globalBuiltinObjectType_; + } + + const STSObjectType *GlobalBuiltinObjectType() const + { + return globalBuiltinObjectType_; + } + + STSObjectType *GlobalBuiltinClassType() + { + return globalBuiltinClassType_; + } + + const STSObjectType *GlobalBuiltinClassType() const + { + return globalBuiltinClassType_; + } + + const STSObjectType *GlobalBuiltinExceptionType() const + { + return globalBuiltinExceptionType_; + } + + checker::WrapperDesc PrimitiveWrapper() const + { + return primitiveWrappers_.Wrappers(); + } + + GlobalArraySignatureMap &GlobalArrayTypes() + { + return globalArraySignatures_; + } + + const GlobalArraySignatureMap &GlobalArrayTypes() const + { + return globalArraySignatures_; + } + + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; + Type *CheckTypeCached(ir::Expression *expr) override; + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override; + + // Object + STSObjectType *BuildClassProperties(ir::ClassDefinition *classDef); + STSObjectType *BuildAnonymousClassProperties(ir::ClassDefinition *classDef, STSObjectType *superType); + STSObjectType *BuildInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl); + STSObjectType *GetSuperType(STSObjectType *type); + ArenaVector GetInterfaces(STSObjectType *type); + ArenaVector GetInterfacesOfClass(STSObjectType *type); + ArenaVector GetInterfacesOfInterface(STSObjectType *type); + void ValidateImplementedInterface(STSObjectType *type, Type *interface, std::unordered_set *extendsSet, + const lexer::SourcePosition &pos); + void ResolveDeclaredMembersOfObject(STSObjectType *type); + Type *ValidateArrayIndex(ir::Expression *expr); + Type *CheckArrayElementAccess(ir::MemberExpression *expr); + STSObjectType *CheckThisOrSuperAccess(ir::Expression *node, STSObjectType *classType, std::string_view msg); + void CreateTypeForClassTypeParameters(STSObjectType *type); + void CreateTypeForInterfaceTypeParameters(STSObjectType *type); + void SetTypeParameterType(ir::TSTypeParameter *typeParam, Type *assemblerType); + void ValidateOverriding(STSObjectType *classType, const lexer::SourcePosition &pos); + void AddImplementedSignature(std::vector *implementedSignatures, binder::LocalVariable *function, + STSFunctionType *it); + void CheckInnerClassMembers(const STSObjectType *classType); + void CheckClassDefinition(ir::ClassDefinition *classDef); + void FindAssignment(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized); + void FindAssignments(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized); + void CheckConstFields(const STSObjectType *classType); + void CheckConstFieldInitialized(const STSObjectType *classType, binder::LocalVariable *prop); + void CheckConstFieldInitialized(const Signature *signature, binder::LocalVariable *prop); + void ComputeAbstractsFromInterface(STSObjectType *interfaceType); + ArenaVector &GetAbstractsForClass(STSObjectType *classType); + const std::vector CollectAbstractSignaturesFromObject(STSObjectType *objType); + void CreateFunctionTypesFromAbstracts(const std::vector &abstracts, + ArenaVector *target); + void CheckCyclicContructorCall(Signature *signature); + + // Type creation + ByteType *CreateByteType(int8_t value); + STSBooleanType *CreateSTSBooleanType(bool value); + DoubleType *CreateDoubleType(double value); + FloatType *CreateFloatType(float value); + IntType *CreateIntType(int32_t value); + LongType *CreateLongType(int64_t value); + ShortType *CreateShortType(int16_t value); + CharType *CreateCharType(char16_t value); + STSStringType *CreateSTSStringType(util::StringView value); + STSArrayType *CreateSTSArrayType(Type *elementType); + STSFunctionType *CreateSTSFunctionType(Signature *signature); + STSFunctionType *CreateSTSFunctionType(util::StringView name); + STSTypeReference *CreateTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *refVar); + STSTypeParameter *CreateTypeParameter(Type *assemblerType); + STSObjectType *CreateSTSObjectType(util::StringView name, ir::AstNode *declNode, STSObjectFlags flags); + std::tuple CreateBuiltinArraySignatureInfo(STSArrayType *arrayType, size_t dim); + Signature *CreateBuiltinArraySignature(STSArrayType *arrayType, size_t dim); + IntType *CreateIntTypeFromType(Type *type); + STSObjectType *CreateNewSTSObjectType(util::StringView name, ir::AstNode *declNode, STSObjectFlags flags); + + Signature *CreateSignature(SignatureInfo *info, Type *returnType, ir::ScriptFunction *func); + Signature *CreateSignature(SignatureInfo *info, Type *returnType, util::StringView internalName); + SignatureInfo *CreateSignatureInfo(); + + // Arithmetic + Type *NegateNumericType(Type *type, ir::Expression *node); + Type *BitwiseNegateIntegralType(Type *type, ir::Expression *node); + std::tuple CheckBinaryOperator(ir::Expression *left, ir::Expression *right, + lexer::TokenType operationType, lexer::SourcePosition pos); + Type *HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + template + Type *PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + + Type *HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + template + Type *PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + + // Function + bool ValidateSignature(Signature *signature, const ArenaVector &arguments, + const lexer::SourcePosition &pos, TypeRelationFlag initialFlags); + Signature *ValidateSignatures(ArenaVector &signatures, const ArenaVector &arguments, + const lexer::SourcePosition &pos, std::string_view signatureKind, + TypeRelationFlag flags); + Signature *ResolveCallExpression(ArenaVector &signatures, + const ArenaVector &arguments, const lexer::SourcePosition &pos, + bool isIdentifier); + + Signature *ResolveConstructExpression(STSObjectType *type, const ArenaVector &arguments, + const lexer::SourcePosition &pos); + checker::STSFunctionType *BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig = false); + checker::STSFunctionType *BuildMethodSignature(ir::MethodDefinition *method); + Signature *CheckEveryAbstractSignatureIsOverriden(STSFunctionType *target, STSFunctionType *source); + Signature *GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef); + void CheckIdenticalOverloads(STSFunctionType *func, STSFunctionType *overload, + const lexer::SourcePosition &overloadStart); + void CheckOverride(Signature *signature); + bool CheckOverride(Signature *signature, STSObjectType *site); + std::tuple CheckOverride(Signature *signature, Signature *other); + bool IsMethodOverridesOther(Signature *target, Signature *source); + bool IsOverridableIn(Signature *signature); + void ValidateSignatureAccessibility(STSObjectType *callee, Signature *signature, const lexer::SourcePosition &pos); + + // Helpers + Type *GetReferencedTypeFromBase(Type *baseType, ir::Expression *name); + Type *GetReferencedTypeBase(ir::Expression *name); + Type *GetTypeFromInterfaceReference(binder::Variable *var); + Type *GetTypeFromClassReference(binder::Variable *var); + Type *GetTypeFromEnumReference(binder::Variable *var); + Type *GetTypeFromTypeParameterReference(binder::LocalVariable *var, const lexer::SourcePosition &pos); + Type *GetDefaultTypeFromPrimitiveType(Type *type); + bool IsConstantExpression(ir::Expression *expr, Type *type); + void ValidateUnaryOperatorOperand(binder::Variable *variable); + std::tuple ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test); + Type *ApplyUnaryOperatorPromotion(Type *type, bool createConst = true); + Type *HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType); + checker::Type *CheckVariableDeclaration(checker::STSChecker *checker, ir::Identifier *ident, + ir::TypeNode *typeAnnotation, ir::Expression *init, + ir::ModifierFlags flags); + void CheckTruthinessOfType(Type *type, const lexer::SourcePosition &pos); + void ConcantConstantString(util::UString &target, Type *type); + Type *HandleStringConcatenation(Type *leftType, Type *rightType); + Type *ResolveIdentifier(ir::Identifier *ident); + STSFunctionType *FindFunctionInVectorGivenByName(util::StringView name, ArenaVector &list); + void MergeComputedAbstracts(ArenaVector &merged, ArenaVector ¤t); + void MergeSignatures(STSFunctionType *target, STSFunctionType *source); + ir::AstNode *FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type); + util::StringView GetContainingObjectNameFromSignature(Signature *signature); + bool IsFunctionContainsSignature(STSFunctionType *funcType, Signature *signature); + void CheckFunctionContainsClashingSignature(const STSFunctionType *funcType, Signature *signature); + bool IsTypeBuiltinType(Type *type); + const ir::AstNode *FindJumpTarget(ir::AstNodeType nodeType, const ir::AstNode *node, const ir::Identifier *target); + void ValidatePropertyAccess(binder::Variable *var, STSObjectType *obj, const lexer::SourcePosition &pos); + binder::VariableFlags GetAccessFlagFromNode(const ir::AstNode *node); + + // Exception + STSObjectType *CheckExceptionType(checker::Type *type, lexer::SourcePosition pos); + STSObjectType *CheckRuntimeExceptionType(checker::Type *type, lexer::SourcePosition pos); + + static Type *TryToInstantiate(Type *type, ArenaAllocator *allocator, TypeRelation *relation, + GlobalTypesHolder *globalTypes); + +private: + void CreateTypeForTypeParameters(STSObjectType *type, ir::TSTypeParameterDeclaration *typeParams); + STSObjectType *CheckException(checker::Type *type, lexer::SourcePosition pos, STSObjectType *expected, + std::string_view msg); + STSObjectType *CreateSTSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, STSObjectFlags flags); + void CheckProgram(parser::Program *program, bool runAnalysis = false); + void InitializeRecordElements(binder::STSBinder *binder, binder::RecordTable *recordTable); + + template + UType HandleModulo(UType leftValue, UType rightValue); + + template + UType HandleBitWiseArithmetic(UType leftValue, UType rightValue, lexer::TokenType operationType); + + template + typename TargetType::UType GetOperand(Type *type); + + ArrayMap arrayTypes_; + GlobalArraySignatureMap globalArraySignatures_; + PrimitiveWrappers primitiveWrappers_; + ComputedAbstracts cachedComputedAbstracts_; + STSObjectType *globalBuiltinStringType_ {}; + STSObjectType *globalBuiltinObjectType_ {}; + STSObjectType *globalBuiltinExceptionType_ {}; + STSObjectType *globalBuiltinRuntimeExceptionType_ {}; + STSObjectType *globalBuiltinClassType_ {}; +}; + +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/checker/TSchecker.cpp b/checker/TSchecker.cpp new file mode 100644 index 000000000..fee813306 --- /dev/null +++ b/checker/TSchecker.cpp @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TSchecker.h" + +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool TSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + binder->IdentifierAnalysis(); + + if (options.dumpAst) { + std::cout << program_->Dump() << std::endl; + } + + if (options.parseOnly) { + return false; + } + + ASSERT(program_->Ast()->IsProgram()); + program_->Ast()->Check(this); + + return false; +} + +Type *TSChecker::CheckTypeCached(ir::Expression *expr) +{ + if (!expr->TsType()) { + expr->SetTsType(expr->Check(this)); + } + + return expr->TsType(); +} + +} // namespace panda::es2panda::checker diff --git a/typescript/checker.h b/checker/TSchecker.h similarity index 51% rename from typescript/checker.h rename to checker/TSchecker.h index dd3365372..6c475a4e1 100644 --- a/typescript/checker.h +++ b/checker/TSchecker.h @@ -13,14 +13,13 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_CHECKER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_CHECKER_H +#ifndef ES2PANDA_CHECKER_TS_CHECKER_H +#define ES2PANDA_CHECKER_TS_CHECKER_H +#include "plugins/ecmascript/es2panda/checker/checker.h" #include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" -#include "plugins/ecmascript/es2panda/typescript/core/checkerContext.h" -#include "plugins/ecmascript/es2panda/typescript/types/globalTypesHolder.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" -#include "plugins/ecmascript/es2panda/typescript/types/types.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/types.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include "macros.h" @@ -104,36 +103,10 @@ enum class AstNodeType; } // namespace panda::es2panda::ir namespace panda::es2panda::checker { -using StringLiteralPool = std::unordered_map; -using NumberLiteralPool = std::unordered_map; -using FunctionParamsResolveResult = std::variant &, bool>; -using InterfacePropertyMap = std::unordered_map>; -using TypeOrNode = std::variant; -using IndexInfoTypePair = std::pair; -using PropertyMap = std::unordered_map; -using ArgRange = std::pair; - -class Checker { -public: - explicit Checker(ArenaAllocator *allocator, binder::Binder *binder); - ~Checker() = default; - NO_COPY_SEMANTIC(Checker); - NO_MOVE_SEMANTIC(Checker); - ArenaAllocator *Allocator() const - { - return allocator_; - } - - binder::Binder *Binder() - { - return binder_; - } - - binder::Scope *Scope() const - { - return scope_; - } +class TSChecker : public Checker { +public: + explicit TSChecker() : Checker() {} Type *GlobalNumberType() { @@ -250,26 +223,6 @@ public: return globalTypes_->GlobalErrorType(); } - CheckerContext Context() - { - return context_; - } - - bool HasStatus(CheckerStatus status) - { - return (context_.Status() & status) != 0; - } - - void RemoveStatus(CheckerStatus status) - { - context_.Status() &= ~status; - } - - void AddStatus(CheckerStatus status) - { - context_.Status() |= status; - } - NumberLiteralPool &NumberLiteralMap() { return numberLiteralMap_; @@ -285,82 +238,44 @@ public: return bigintLiteralMap_; } - TypeRelation *Relation() - { - return relation_; - } - - RelationHolder &IdenticalResults() - { - return identicalResults_; - } - - RelationHolder &AssignableResults() - { - return assignableResults_; - } - - RelationHolder &ComparableResults() - { - return comparableResults_; - } - - std::unordered_set &TypeStack() - { - return typeStack_; - } - - std::unordered_map &NodeCache() - { - return nodeCache_; - } - - void StartChecker(); - - Type *CheckTypeCached(const ir::Expression *expr); - - [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos); - [[noreturn]] void ThrowTypeError(std::initializer_list list, - const lexer::SourcePosition &pos); + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; + Type *CheckTypeCached(ir::Expression *expr) override; // Util - static bool InAssignment(const ir::AstNode *node); + static bool InAssignment(ir::AstNode *node); static bool IsAssignmentOperator(lexer::TokenType op); static bool IsLiteralType(const Type *type); - static const ir::AstNode *FindAncestorGivenByType(const ir::AstNode *node, ir::AstNodeType type); - static const ir::AstNode *FindAncestorUntilGivenType(const ir::AstNode *node, ir::AstNodeType stop); + static ir::AstNode *FindAncestorUntilGivenType(ir::AstNode *node, ir::AstNodeType stop); static bool MaybeTypeOfKind(const Type *type, TypeFlag flags); static bool MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind); - static bool IsConstantMemberAccess(const ir::Expression *expr); - static bool IsStringLike(const ir::Expression *expr); - static const ir::TSQualifiedName *ResolveLeftMostQualifiedName(const ir::TSQualifiedName *qualifiedName); - static const ir::MemberExpression *ResolveLeftMostMemberExpression(const ir::MemberExpression *expr); + static bool IsConstantMemberAccess(ir::Expression *expr); + static bool IsStringLike(ir::Expression *expr); + static ir::MemberExpression *ResolveLeftMostMemberExpression(ir::MemberExpression *expr); // Helpers void CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo); Type *CheckNonNullType(Type *type, lexer::SourcePosition lineInfo); Type *GetBaseTypeOfLiteralType(Type *type); - void CheckReferenceExpression(const ir::Expression *expr, const char *invalidReferenceMsg, + void CheckReferenceExpression(ir::Expression *expr, const char *invalidReferenceMsg, const char *invalidOptionalChainMsg); - void CheckTestingKnownTruthyCallableOrAwaitableType(const ir::Expression *condExpr, Type *type, - const ir::AstNode *body); + void CheckTestingKnownTruthyCallableOrAwaitableType(ir::Expression *condExpr, Type *type, ir::AstNode *body); Type *ExtractDefinitelyFalsyTypes(Type *type); Type *RemoveDefinitelyFalsyTypes(Type *type); TypeFlag GetFalsyFlags(Type *type); - bool IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::Variable *searchVar); - bool FindVariableInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar); - bool IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar); + bool IsVariableUsedInConditionBody(ir::AstNode *parent, binder::Variable *searchVar); + bool FindVariableInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar); + bool IsVariableUsedInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar); [[noreturn]] void ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, lexer::SourcePosition lineInfo); [[noreturn]] void ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType = false); - void ElaborateElementwise(Type *targetType, const ir::Expression *sourceNode, const lexer::SourcePosition &pos); - void InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *declarator); - Type *GetTypeOfVariable(binder::Variable *var); + void ElaborateElementwise(Type *targetType, ir::Expression *sourceNode, const lexer::SourcePosition &pos); + void InferSimpleVariableDeclaratorType(ir::VariableDeclarator *declarator); + Type *GetTypeOfVariable(binder::Variable *var) override; Type *GetUnaryResultType(Type *operandType); - Type *GetTypeFromClassOrInterfaceReference(const ir::TSTypeReference *node, binder::Variable *var); - Type *GetTypeFromTypeAliasReference(const ir::TSTypeReference *node, binder::Variable *var); - Type *GetTypeReferenceType(const ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeFromClassOrInterfaceReference(ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeFromTypeAliasReference(ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeReferenceType(ir::TSTypeReference *node, binder::Variable *var); // Type creation Type *CreateNumberLiteralType(double value); @@ -379,12 +294,12 @@ public: Type *CreateObjectTypeWithConstructSignature(Signature *constructSignature); // Object - void ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expression *member, - ArenaVector &signatureDeclarations, - ArenaVector &indexDeclarations, bool isInterface); + void ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member, + ArenaVector &signatureDeclarations, + ArenaVector &indexDeclarations, bool isInterface); void ResolveSignaturesOfObjectType(ObjectType *type, - ArenaVector &signatureDeclarations); - void ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations); + ArenaVector &signatureDeclarations); + void ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations); void ResolveDeclaredMembers(InterfaceType *type); bool ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, const lexer::SourcePosition &locInfo); @@ -393,142 +308,64 @@ public: binder::Variable *GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, binder::VariableFlags propagateFlags); void CheckIndexConstraints(Type *type); - void ResolveStructuredTypeMembers(Type *type); void ResolveUnionTypeMembers(UnionType *type); void ResolveObjectTypeMembers(ObjectType *type); void ResolveInterfaceOrClassTypeMembers(InterfaceType *type); - Type *CheckComputedPropertyName(const ir::Expression *key); + Type *CheckComputedPropertyName(ir::Expression *key); Type *GetPropertyTypeForIndexType(Type *type, Type *indexType); IndexInfo *GetApplicableIndexInfo(Type *type, Type *indexType); ArenaVector GetBaseTypes(InterfaceType *type); + void ResolveStructuredTypeMembers(Type *type) override; // Function - Type *HandleFunctionReturn(const ir::ScriptFunction *func); + Type *HandleFunctionReturn(ir::ScriptFunction *func); void CheckFunctionParameterDeclarations(const ArenaVector ¶ms, SignatureInfo *signatureInfo); std::tuple CheckFunctionParameter( - const ir::Expression *param, SignatureInfo *signatureInfo); + ir::Expression *param, SignatureInfo *signatureInfo); std::tuple CheckFunctionIdentifierParameter( - const ir::Identifier *param); + ir::Identifier *param); std::tuple CheckFunctionAssignmentPatternParameter( - const ir::AssignmentExpression *param); + ir::AssignmentExpression *param); std::tuple CheckFunctionRestParameter( - const ir::SpreadElement *param, SignatureInfo *signatureInfo); + ir::SpreadElement *param, SignatureInfo *signatureInfo); std::tuple CheckFunctionArrayPatternParameter( - const ir::ArrayExpression *param); + ir::ArrayExpression *param); std::tuple CheckFunctionObjectPatternParameter( - const ir::ObjectExpression *param); + ir::ObjectExpression *param); void InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar); - void CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaVector *returnTypes); - void CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction *func, lexer::SourcePosition lineInfo, + void CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector *returnTypes); + void CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, lexer::SourcePosition lineInfo, const char *errMsg); - void CreatePatternParameterName(const ir::AstNode *node, std::stringstream &ss); - void ThrowReturnTypeCircularityError(const ir::ScriptFunction *func); + void CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss); + void ThrowReturnTypeCircularityError(ir::ScriptFunction *func); ArgRange GetArgRange(const ArenaVector &signatures, ArenaVector *potentialSignatures, uint32_t callArgsSize, bool *haveSignatureWithRest); bool CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError); Type *resolveCallOrNewExpression(const ArenaVector &signatures, ArenaVector arguments, const lexer::SourcePosition &errPos); - Type *CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpression *arrayPattern, Type *inferedType); - Type *CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExpression *objectPattern, Type *inferedType); - - // Type relation - bool IsTypeIdenticalTo(Type *source, Type *target); - bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool IsTypeAssignableTo(Type *source, Type *target); - bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool IsTypeComparableTo(Type *source, Type *target); - bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool AreTypesComparable(Type *source, Type *target); - bool IsTypeEqualityComparableTo(Type *source, Type *target); - bool IsAllTypesAssignableTo(Type *source, Type *target); + Type *CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpression *arrayPattern, Type *inferedType); + Type *CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpression *objectPattern, Type *inferedType); // Binary like expression - Type *CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckCompareOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckAndOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr); - Type *CheckOrOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr); - Type *CheckInstanceofExpression(Type *leftType, Type *rightType, const ir::Expression *rightExpr, - const ir::AstNode *expr); - Type *CheckInExpression(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr); - void CheckAssignmentOperator(lexer::TokenType op, const ir::Expression *leftExpr, Type *leftType, Type *valueType); - - friend class ScopeContext; - friend class SavedCheckerContext; + Type *CheckBinaryOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckPlusOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckCompareOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckAndOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr); + Type *CheckOrOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr); + Type *CheckInstanceofExpression(Type *leftType, Type *rightType, ir::Expression *rightExpr, ir::AstNode *expr); + Type *CheckInExpression(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr); + void CheckAssignmentOperator(lexer::TokenType op, ir::Expression *leftExpr, Type *leftType, Type *valueType); private: - ArenaAllocator *allocator_; - binder::Binder *binder_; - const ir::BlockStatement *rootNode_; - binder::Scope *scope_; - CheckerContext context_; - GlobalTypesHolder *globalTypes_; - NumberLiteralPool numberLiteralMap_; StringLiteralPool stringLiteralMap_; StringLiteralPool bigintLiteralMap_; - - TypeRelation *relation_; - - RelationHolder identicalResults_; - RelationHolder assignableResults_; - RelationHolder comparableResults_; - - std::unordered_set typeStack_; - std::unordered_map nodeCache_; - std::vector scopeStack_; }; -class ScopeContext { -public: - explicit ScopeContext(Checker *checker, binder::Scope *newScope) : checker_(checker), prevScope_(checker_->scope_) - { - checker_->scope_ = newScope; - } - - ~ScopeContext() - { - checker_->scope_ = prevScope_; - } - - NO_COPY_SEMANTIC(ScopeContext); - NO_MOVE_SEMANTIC(ScopeContext); - -private: - Checker *checker_; - binder::Scope *prevScope_; -}; - -class SavedCheckerContext { -public: - explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) - : checker_(checker), prev_(checker->context_) - { - checker_->context_ = CheckerContext(newStatus); - } - - NO_COPY_SEMANTIC(SavedCheckerContext); - DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); - - ~SavedCheckerContext() - { - checker_->context_ = prev_; - } - -private: - Checker *checker_; - CheckerContext prev_; -}; } // namespace panda::es2panda::checker #endif /* CHECKER_H */ diff --git a/typescript/core/typeRelation.cpp b/checker/checker.cpp similarity index 57% rename from typescript/core/typeRelation.cpp rename to checker/checker.cpp index 4bd2675be..828e8d35d 100644 --- a/typescript/core/typeRelation.cpp +++ b/checker/checker.cpp @@ -13,11 +13,77 @@ * limitations under the License. */ -#include "plugins/ecmascript/es2panda/typescript/checker.h" - -#include +#include "checker.h" + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +#include +#include +#include namespace panda::es2panda::checker { +Checker::Checker() + : allocator_(SpaceType::SPACE_TYPE_COMPILER, nullptr, true), + context_(CheckerStatus::NO_OPTS), + globalTypes_(allocator_.New(&allocator_)), + relation_(allocator_.New(this)) +{ +} + +void Checker::Initialize(binder::Binder *binder) +{ + binder_ = binder; + scope_ = binder_->TopScope(); + program_ = binder_->Program(); +} + +void Checker::ThrowTypeError(std::initializer_list list, const lexer::SourcePosition &pos) +{ + std::stringstream ss; + + for (const auto &it : list) { + if (std::holds_alternative(it)) { + ss << std::get(it); + } else if (std::holds_alternative(it)) { + ss << std::get(it); + } else if (std::holds_alternative(it)) { + ss << TokenToString(std::get(it)); + } else if (std::holds_alternative(it)) { + std::get(it)->ToString(ss); + } else if (std::holds_alternative(it)) { + std::get(it).GetType()->ToStringAsSrc(ss); + } else if (std::holds_alternative(it)) { + ss << std::to_string(std::get(it)); + } else if (std::holds_alternative(it)) { + std::get(it)->ToString(ss, nullptr, true); + } else { + UNREACHABLE(); + } + } + + std::string err = ss.str(); + ThrowTypeError(err, pos); +} + +void Checker::ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos) +{ + lexer::LineIndex index(program_->SourceCode()); + lexer::SourceLocation loc = index.GetLocation(pos); + + throw Error {ErrorType::TYPE, program_->SourceFile().Utf8(), message, loc.line, loc.col}; +} + bool Checker::IsAllTypesAssignableTo(Type *source, Type *target) { if (source->TypeFlags() == TypeFlag::UNION) { @@ -114,4 +180,5 @@ bool Checker::IsTypeEqualityComparableTo(Type *source, Type *target) { return target->HasTypeFlag(TypeFlag::NULLABLE) || IsTypeComparableTo(source, target); } + } // namespace panda::es2panda::checker diff --git a/checker/checker.h b/checker/checker.h new file mode 100644 index 000000000..3df9e9410 --- /dev/null +++ b/checker/checker.h @@ -0,0 +1,269 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_CHECKER_CHECKER_H +#define ES2PANDA_CHECKER_CHECKER_H + +#include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" +#include "plugins/ecmascript/es2panda/checker/checkerContext.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "macros.h" + +#include +#include +#include +#include + +namespace panda::es2panda::parser { +class Program; +} // namespace panda::es2panda::parser + +namespace panda::es2panda::ir { +class AstNode; +class Expression; +class BlockStatement; +enum class AstNodeType; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { +class Binder; +class Decl; +class EnumVariable; +class FunctionDecl; +class LocalVariable; +class Scope; +class Variable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +class STSChecker; +class InterfaceType; +class GlobalTypesHolder; + +using StringLiteralPool = std::unordered_map; +using NumberLiteralPool = std::unordered_map; +using FunctionParamsResolveResult = std::variant &, bool>; +using InterfacePropertyMap = std::unordered_map>; +using TypeOrNode = std::variant; +using IndexInfoTypePair = std::pair; +using PropertyMap = std::unordered_map; +using ArgRange = std::pair; + +class Checker { +public: + explicit Checker(); + ~Checker() = default; + NO_COPY_SEMANTIC(Checker); + NO_MOVE_SEMANTIC(Checker); + + ArenaAllocator *Allocator() + { + return &allocator_; + } + + binder::Binder *Binder() + { + return binder_; + } + + binder::Scope *Scope() const + { + return scope_; + } + + CheckerContext &Context() + { + return context_; + } + + bool HasStatus(CheckerStatus status) + { + return (context_.Status() & status) != 0; + } + + void RemoveStatus(CheckerStatus status) + { + context_.Status() &= ~status; + } + + void AddStatus(CheckerStatus status) + { + context_.Status() |= status; + } + + TypeRelation *Relation() + { + return relation_; + } + + GlobalTypesHolder *GetGlobalTypesHolder() + { + return globalTypes_; + } + + RelationHolder &IdenticalResults() + { + return identicalResults_; + } + + RelationHolder &AssignableResults() + { + return assignableResults_; + } + + RelationHolder &ComparableResults() + { + return comparableResults_; + } + + std::unordered_set &TypeStack() + { + return typeStack_; + } + + STSChecker *AsSTSChecker() + { + return reinterpret_cast(this); + } + + virtual bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) = 0; + virtual Type *CheckTypeCached(ir::Expression *expr) = 0; + virtual Type *GetTypeOfVariable(binder::Variable *var) = 0; + virtual void ResolveStructuredTypeMembers(Type *type) = 0; + + [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos); + [[noreturn]] void ThrowTypeError(std::initializer_list list, + const lexer::SourcePosition &pos); + + bool IsTypeIdenticalTo(Type *source, Type *target); + bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool IsTypeAssignableTo(Type *source, Type *target); + bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool IsTypeComparableTo(Type *source, Type *target); + bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool AreTypesComparable(Type *source, Type *target); + bool IsTypeEqualityComparableTo(Type *source, Type *target); + bool IsAllTypesAssignableTo(Type *source, Type *target); + + friend class ScopeContext; + friend class TypeStackElement; + friend class SavedCheckerContext; + +protected: + void Initialize(binder::Binder *binder); + + ArenaAllocator allocator_; + CheckerContext context_; + GlobalTypesHolder *globalTypes_; + TypeRelation *relation_; + binder::Binder *binder_ {}; + parser::Program *program_; + binder::Scope *scope_ {}; + + RelationHolder identicalResults_; + RelationHolder assignableResults_; + RelationHolder comparableResults_; + + std::unordered_set typeStack_; +}; + +class TypeStackElement { +public: + explicit TypeStackElement(Checker *checker, void *element, std::initializer_list list, + const lexer::SourcePosition &pos) + : checker_(checker), element_(element) + { + if (!checker->typeStack_.insert(element).second) { + checker_->ThrowTypeError(list, pos); + } + } + + explicit TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos) + : checker_(checker), element_(element) + { + if (!checker->typeStack_.insert(element).second) { + checker_->ThrowTypeError(err, pos); + } + } + + ~TypeStackElement() + { + checker_->typeStack_.erase(element_); + } + + NO_COPY_SEMANTIC(TypeStackElement); + NO_MOVE_SEMANTIC(TypeStackElement); + +private: + Checker *checker_; + void *element_; +}; + +class ScopeContext { +public: + explicit ScopeContext(Checker *checker, binder::Scope *newScope) : checker_(checker), prevScope_(checker_->scope_) + { + checker_->scope_ = newScope; + } + + ~ScopeContext() + { + checker_->scope_ = prevScope_; + } + + NO_COPY_SEMANTIC(ScopeContext); + NO_MOVE_SEMANTIC(ScopeContext); + +private: + Checker *checker_; + binder::Scope *prevScope_; +}; + +class SavedCheckerContext { +public: + explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) + : SavedCheckerContext(checker, newStatus, nullptr) + { + } + explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, STSObjectType *containingClass) + : checker_(checker), prev_(checker->context_) + { + checker_->context_ = CheckerContext(newStatus, containingClass); + } + + NO_COPY_SEMANTIC(SavedCheckerContext); + DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); + + ~SavedCheckerContext() + { + checker_->context_ = prev_; + } + +private: + Checker *checker_; + CheckerContext prev_; +}; +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/typescript/core/checkerContext.cpp b/checker/checkerContext.cpp similarity index 100% rename from typescript/core/checkerContext.cpp rename to checker/checkerContext.cpp diff --git a/typescript/core/checkerContext.h b/checker/checkerContext.h similarity index 57% rename from typescript/core/checkerContext.h rename to checker/checkerContext.h index 3aef77d60..9f709502e 100644 --- a/typescript/core/checkerContext.h +++ b/checker/checkerContext.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_PARSER_CORE_CHECKER_CONTEXT_H -#define ES2PANDA_PARSER_CORE_CHECKER_CONTEXT_H +#ifndef ES2PANDA_CHECKER_CHECKER_CONTEXT_H +#define ES2PANDA_CHECKER_CHECKER_CONTEXT_H #include #include "plugins/ecmascript/es2panda/util/enumbitops.h" @@ -28,30 +28,61 @@ enum class CheckerStatus : uint32_t { IN_CONST_CONTEXT = 0x2U, KEEP_LITERAL_TYPE = 0x4U, IN_PARAMETER = 0x8U, + IN_CLASS = 0x10U, + IN_INTERFACE = 0x20U, + IN_ABSTRACT = 0x40U, + IN_STATIC_CONTEXT = 0x80U, + IN_CONSTRUCTOR = 0x100U, + IN_STATIC_BLOCK = 0x200U, + INNER_CLASS = 0x400U, }; +class STSObjectType; +class Signature; + DEFINE_BITOPS(CheckerStatus) class CheckerContext { public: - explicit CheckerContext(CheckerStatus newStatus) : status_(newStatus) {} + explicit CheckerContext(CheckerStatus newStatus) : CheckerContext(newStatus, nullptr) {} + explicit CheckerContext(CheckerStatus newStatus, STSObjectType *containingClass) + : status_(newStatus), containingClass_(containingClass) + { + } const CheckerStatus &Status() const { return status_; } + STSObjectType *ContainingClass() const + { + return containingClass_; + } + + Signature *ContainingSignature() const + { + return containingSignature_; + } + CheckerStatus &Status() { return status_; } + void SetContainingSignature(Signature *containingSignature) + { + containingSignature_ = containingSignature; + } + DEFAULT_COPY_SEMANTIC(CheckerContext); DEFAULT_MOVE_SEMANTIC(CheckerContext); ~CheckerContext() = default; private: CheckerStatus status_; + STSObjectType *containingClass_ {}; + Signature *containingSignature_ {nullptr}; }; } // namespace panda::es2panda::checker diff --git a/checker/sts/aliveAnalyzer.cpp b/checker/sts/aliveAnalyzer.cpp new file mode 100644 index 000000000..f8c5fcfbe --- /dev/null +++ b/checker/sts/aliveAnalyzer.cpp @@ -0,0 +1,425 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "aliveAnalyzer.h" + +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/doWhileStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/expressionStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/whileStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/forUpdateStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/forOfStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/ifStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/switchStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/statements/throwStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/switchCaseStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/breakStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/continueStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/returnStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/tryStatement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { + +void AliveAnalyzer::AnalyzeNodes(const ir::AstNode *node) +{ + node->Iterate([this](auto *childNode) { AnalyzeNode(childNode); }); +} + +void AliveAnalyzer::AnalyzeNode(const ir::AstNode *node) +{ + if (!node) { + return; + } + + switch (node->Type()) { + case ir::AstNodeType::EXPRESSION_STATEMENT: { + AnalyzeNode(node->AsExpressionStatement()->GetExpression()); + break; + } + case ir::AstNodeType::CLASS_DECLARATION: { + AnalyzeClassDecl(node->AsClassDeclaration()); + break; + } + case ir::AstNodeType::CLASS_DEFINITION: { + AnalyzeClassDef(node->AsClassDefinition()); + break; + } + case ir::AstNodeType::METHOD_DEFINITION: { + AnalyzeMethodDef(node->AsMethodDefinition()); + break; + } + case ir::AstNodeType::VARIABLE_DECLARATION: { + AnalyzeVarDef(node->AsVariableDeclaration()); + break; + } + case ir::AstNodeType::BLOCK_STATEMENT: { + AnalyzeStats(node->AsBlockStatement()->Statements()); + break; + } + case ir::AstNodeType::DO_WHILE_STATEMENT: { + AnalyzeDoLoop(node->AsDoWhileStatement()); + break; + } + case ir::AstNodeType::WHILE_STATEMENT: { + AnalyzeWhileLoop(node->AsWhileStatement()); + break; + } + case ir::AstNodeType::FOR_UPDATE_STATEMENT: { + AnalyzeForLoop(node->AsForUpdateStatement()); + break; + } + case ir::AstNodeType::FOR_OF_STATEMENT: { + AnalyzeForOfLoop(node->AsForOfStatement()); + break; + } + case ir::AstNodeType::IF_STATEMENT: { + AnalyzeIf(node->AsIfStatement()); + break; + } + case ir::AstNodeType::LABELLED_STATEMENT: { + AnalyzeLabelled(node->AsLabelledStatement()); + break; + } + case ir::AstNodeType::STS_NEW_CLASS_INSTANCE_EXPRESSION: { + AnalyzeNewClass(node->AsSTSNewClassInstanceExpression()); + break; + } + case ir::AstNodeType::CALL_EXPRESSION: { + AnalyzeCall(node->AsCallExpression()); + break; + } + case ir::AstNodeType::THROW_STATEMENT: { + AnalyzeThrow(node->AsThrowStatement()); + break; + } + case ir::AstNodeType::SWITCH_STATEMENT: { + AnalyzeSwitch(node->AsSwitchStatement()); + break; + } + case ir::AstNodeType::TRY_STATEMENT: { + AnalyzeTry(node->AsTryStatement()); + break; + } + case ir::AstNodeType::BREAK_STATEMENT: { + AnalyzeBreak(node->AsBreakStatement()); + break; + } + case ir::AstNodeType::CONTINUE_STATEMENT: { + AnalyzeContinue(node->AsContinueStatement()); + break; + } + case ir::AstNodeType::RETURN_STATEMENT: { + AnalyzeReturn(node->AsReturnStatement()); + break; + } + default: { + break; + } + } +} + +void AliveAnalyzer::AnalyzeDef(const ir::AstNode *node) +{ + AnalyzeStat(node); + if (node && node->IsClassStaticBlock() && status_ == LivenessStatus::DEAD) { + checker_->ThrowTypeError("Initializer must be able to complete normally.", node->Start()); + } +} + +void AliveAnalyzer::AnalyzeStat(const ir::AstNode *node) +{ + if (!node) { + return; + } + + if (status_ == LivenessStatus::DEAD) { + checker_->ThrowTypeError("Unreachable statement.", node->Start()); + } + + if (node->IsClassStaticBlock()) { + AnalyzeNodes(node); + return; + } + + AnalyzeNode(node); +} + +void AliveAnalyzer::AnalyzeStats(const ArenaVector &stats) +{ + for (const auto *it : stats) { + AnalyzeStat(it); + } +} + +void AliveAnalyzer::ClearPendingExits() +{ + pendingExits_.clear(); +} + +static bool IsStaticMember(const ir::AstNode *node) +{ + switch (node->Type()) { + case ir::AstNodeType::CLASS_PROPERTY: { + return node->IsStatic(); + } + case ir::AstNodeType::CLASS_DECLARATION: { + return node->AsClassDeclaration()->Definition()->IsStatic(); + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + return node->IsStatic(); + } + default: { + return false; + } + } +} + +void AliveAnalyzer::AnalyzeClassDecl(const ir::ClassDeclaration *classDecl) +{ + for (const auto *it : classDecl->Definition()->Body()) { + AnalyzeNode(it); + } +} + +void AliveAnalyzer::AnalyzeClassDef(const ir::ClassDefinition *classDef) +{ + if (!classDef->Variable()) { + return; + } + + LivenessStatus prevStatus = status_; + PendingExitsVector oldPendingExits = std::move(pendingExits_); + + for (const auto *it : classDef->Body()) { + if (!it->IsMethodDefinition() && IsStaticMember(it)) { + AnalyzeDef(it); + ClearPendingExits(); + } + } + + for (const auto *it : classDef->Body()) { + if (!it->IsMethodDefinition() && !IsStaticMember(it)) { + AnalyzeDef(it); + ClearPendingExits(); + } + } + + for (const auto *it : classDef->Body()) { + if (it->IsClassStaticBlock()) { + AnalyzeDef(it); + break; + } + } + + for (const auto *it : classDef->Body()) { + if (it->IsMethodDefinition()) { + AnalyzeNode(it); + } + } + + pendingExits_ = std::move(oldPendingExits); + status_ = prevStatus; +} + +void AliveAnalyzer::AnalyzeMethodDef(const ir::MethodDefinition *methodDef) +{ + auto *func = methodDef->Function(); + + if (!func->Body()) { + return; + } + + status_ = LivenessStatus::ALIVE; + AnalyzeStat(func->Body()); + ASSERT(methodDef->TsType() && methodDef->TsType()->IsSTSFunctionType()); + + if (status_ == LivenessStatus::ALIVE && + !methodDef->TsType()->AsSTSFunctionType()->FindSignature(func)->ReturnType()->IsSTSVoidType()) { + checker_->ThrowTypeError("Function with a non void return type must return a value.", func->Id()->Start()); + } + + ClearPendingExits(); +} + +void AliveAnalyzer::AnalyzeVarDef(const ir::VariableDeclaration *varDef) +{ + for (auto *it : varDef->Declarators()) { + if (!it->Init()) { + continue; + } + + AnalyzeNode(it->Init()); + } +} + +void AliveAnalyzer::AnalyzeDoLoop(const ir::DoWhileStatement *doWhile) +{ + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeStat(doWhile->Body()); + status_ = Or(status_, ResolveContinues(doWhile)); + AnalyzeNode(doWhile->Test()); + ASSERT(doWhile->Test()->TsType() && doWhile->Test()->TsType()->IsSTSBooleanType()); + auto *condType = doWhile->Test()->TsType()->AsSTSBooleanType(); + status_ = + And(status_, static_cast(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); + status_ = Or(status_, ResolveBreaks(doWhile, oldPendingExits)); +} + +void AliveAnalyzer::AnalyzeWhileLoop(const ir::WhileStatement *whileStmt) +{ + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeNode(whileStmt->Test()); + ASSERT(whileStmt->Test()->TsType() && whileStmt->Test()->TsType()->IsSTSBooleanType()); + auto *condType = whileStmt->Test()->TsType()->AsSTSBooleanType(); + status_ = And(status_, + static_cast(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && !condType->GetValue()))); + AnalyzeStat(whileStmt->Body()); + status_ = Or(status_, ResolveContinues(whileStmt)); + status_ = Or(ResolveBreaks(whileStmt, oldPendingExits), + From(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); +} + +void AliveAnalyzer::AnalyzeForLoop(const ir::ForUpdateStatement *forStmt) +{ + AnalyzeNode(forStmt->Init()); + PendingExitsVector oldPendingExits = std::move(pendingExits_); + const STSBooleanType *condType {}; + if (forStmt->Test()) { + AnalyzeNode(forStmt->Test()); + ASSERT(forStmt->Test()->TsType() && forStmt->Test()->TsType()->IsSTSBooleanType()); + condType = forStmt->Test()->TsType()->AsSTSBooleanType(); + status_ = From(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && !condType->GetValue())); + } else { + status_ = LivenessStatus::ALIVE; + } + + AnalyzeStat(forStmt->Body()); + status_ = Or(status_, ResolveContinues(forStmt)); + AnalyzeNode(forStmt->Update()); + status_ = Or(ResolveBreaks(forStmt, oldPendingExits), + From(condType && !(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); +} + +void AliveAnalyzer::AnalyzeForOfLoop(const ir::ForOfStatement *forOfStmt) +{ + ASSERT(forOfStmt->Left()->IsVariableDeclaration()); + AnalyzeVarDef(forOfStmt->Left()->AsVariableDeclaration()); + AnalyzeNode(forOfStmt->Right()); + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeStat(forOfStmt->Body()); + status_ = Or(status_, ResolveContinues(forOfStmt)); + ResolveBreaks(forOfStmt, oldPendingExits); + status_ = LivenessStatus::ALIVE; +} + +void AliveAnalyzer::AnalyzeIf(const ir::IfStatement *ifStmt) +{ + AnalyzeNode(ifStmt->Test()); + AnalyzeStat(ifStmt->Consequent()); + if (ifStmt->Alternate()) { + LivenessStatus prevStatus = status_; + status_ = LivenessStatus::ALIVE; + AnalyzeStat(ifStmt->Alternate()); + status_ = Or(status_, prevStatus); + } else { + status_ = LivenessStatus::ALIVE; + } +} + +void AliveAnalyzer::AnalyzeLabelled(const ir::LabelledStatement *labelledStmt) +{ + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeStat(labelledStmt->Body()); + status_ = Or(status_, ResolveBreaks(labelledStmt, oldPendingExits)); +} + +void AliveAnalyzer::AnalyzeNewClass(const ir::STSNewClassInstanceExpression *newClass) +{ + for (const auto *it : newClass->GetArguments()) { + AnalyzeNode(it); + } + + if (newClass->ClassDefinition()) { + AnalyzeNode(newClass->ClassDefinition()); + } +} + +void AliveAnalyzer::AnalyzeCall(const ir::CallExpression *callExpr) +{ + AnalyzeNode(callExpr->Callee()); + for (const auto *it : callExpr->Arguments()) { + AnalyzeNode(it); + } +} + +void AliveAnalyzer::AnalyzeThrow(const ir::ThrowStatement *throwStmt) +{ + AnalyzeNode(throwStmt->Argument()); + MarkDead(); +} + +void AliveAnalyzer::AnalyzeSwitch(const ir::SwitchStatement *switchStmt) +{ + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeNode(switchStmt->Discriminant()); + + std::vector constants; + for (const auto *it : switchStmt->Cases()) { + status_ = LivenessStatus::ALIVE; + AnalyzeNode(it->Test()); + AnalyzeStats(it->Consequent()); + } + + status_ = Or(status_, ResolveBreaks(switchStmt, oldPendingExits)); +} + +void AliveAnalyzer::AnalyzeBreak(const ir::BreakStatement *breakStmt) +{ + RecordExit(PendingExit(breakStmt)); +} + +void AliveAnalyzer::AnalyzeContinue(const ir::ContinueStatement *contStmt) +{ + RecordExit(PendingExit(contStmt)); +} + +void AliveAnalyzer::AnalyzeReturn(const ir::ReturnStatement *retStmt) +{ + AnalyzeNode(retStmt->Argument()); + RecordExit(PendingExit(retStmt)); +} + +void AliveAnalyzer::AnalyzeTry([[maybe_unused]] const ir::TryStatement *tryStmt) +{ + // TODO +} +} // namespace panda::es2panda::checker diff --git a/checker/sts/aliveAnalyzer.h b/checker/sts/aliveAnalyzer.h new file mode 100644 index 000000000..259009bfa --- /dev/null +++ b/checker/sts/aliveAnalyzer.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_ALIVE_ANALYZER_H +#define ES2PANDA_COMPILER_CHECKER_STS_ALIVE_ANALYZER_H + +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/checker/sts/baseAnalyzer.h" + +#include "utils/arena_containers.h" + +namespace panda::es2panda::ir { +class AstNode; +class Statement; +class ClassDefinition; +class MethodDefinition; +class DoWhileStatement; +class VariableDeclaration; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class AliveAnalyzer : public BaseAnalyzer { +public: + AliveAnalyzer(const ir::AstNode *node, STSChecker *checker) : BaseAnalyzer(), checker_(checker) + { + AnalyzeNodes(node); + } + + void MarkDead() override + { + status_ = LivenessStatus::DEAD; + } + + LivenessStatus Or(LivenessStatus left, LivenessStatus right) + { + return static_cast(left | right); + } + + LivenessStatus And(LivenessStatus left, LivenessStatus right) + { + return static_cast(left & right); + } + +private: + void ClearPendingExits(); + void AnalyzeNodes(const ir::AstNode *node); + void AnalyzeNode(const ir::AstNode *node); + void AnalyzeDef(const ir::AstNode *node); + void AnalyzeStat(const ir::AstNode *node); + void AnalyzeStats(const ArenaVector &stats); + void AnalyzeClassDecl(const ir::ClassDeclaration *classDecl); + void AnalyzeClassDef(const ir::ClassDefinition *classDef); + void AnalyzeMethodDef(const ir::MethodDefinition *methodDef); + void AnalyzeVarDef(const ir::VariableDeclaration *varDef); + void AnalyzeDoLoop(const ir::DoWhileStatement *doWhile); + void AnalyzeWhileLoop(const ir::WhileStatement *whileStmt); + void AnalyzeForLoop(const ir::ForUpdateStatement *forStmt); + void AnalyzeForOfLoop(const ir::ForOfStatement *forOfStmt); + void AnalyzeIf(const ir::IfStatement *ifStmt); + void AnalyzeLabelled(const ir::LabelledStatement *labelledStmt); + void AnalyzeNewClass(const ir::STSNewClassInstanceExpression *newClass); + void AnalyzeCall(const ir::CallExpression *callExpr); + void AnalyzeThrow(const ir::ThrowStatement *throwStmt); + void AnalyzeSwitch(const ir::SwitchStatement *switchStmt); + void AnalyzeTry(const ir::TryStatement *tryStmt); + void AnalyzeBreak(const ir::BreakStatement *breakStmt); + void AnalyzeContinue(const ir::ContinueStatement *contStmt); + void AnalyzeReturn(const ir::ReturnStatement *retStmt); + + STSChecker *checker_; + LivenessStatus status_ {LivenessStatus::ALIVE}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/sts/arithmetic.cpp b/checker/sts/arithmetic.cpp new file mode 100644 index 000000000..2d0d74485 --- /dev/null +++ b/checker/sts/arithmetic.cpp @@ -0,0 +1,327 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "arithmetic.h" + +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { + +Type *STSChecker::NegateNumericType(Type *type, ir::Expression *node) +{ + ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::STS_NUMERIC)); + + TypeFlag typeKind = STSType(type); + Type *result = nullptr; + + switch (typeKind) { + case TypeFlag::BYTE: { + result = CreateByteType(-(type->AsByteType()->GetValue())); + break; + } + case TypeFlag::CHAR: { + result = CreateCharType(-(type->AsCharType()->GetValue())); + break; + } + case TypeFlag::SHORT: { + result = CreateShortType(-(type->AsShortType()->GetValue())); + break; + } + case TypeFlag::INT: { + result = CreateIntType(-(type->AsIntType()->GetValue())); + break; + } + case TypeFlag::LONG: { + result = CreateLongType(-(type->AsLongType()->GetValue())); + break; + } + case TypeFlag::FLOAT: { + result = CreateFloatType(-(type->AsFloatType()->GetValue())); + break; + } + case TypeFlag::DOUBLE: { + result = CreateDoubleType(-(type->AsDoubleType()->GetValue())); + break; + } + default: { + UNREACHABLE(); + } + } + + node->SetTsType(result); + return result; +} + +Type *STSChecker::BitwiseNegateIntegralType(Type *type, ir::Expression *node) +{ + ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::STS_INTEGRAL)); + + TypeFlag typeKind = STSType(type); + + Type *result = nullptr; + + switch (typeKind) { + case TypeFlag::BYTE: { + result = CreateByteType(~(type->AsByteType()->GetValue())); + break; + } + case TypeFlag::CHAR: { + result = CreateCharType(~(type->AsCharType()->GetValue())); + break; + } + case TypeFlag::SHORT: { + result = CreateShortType(~(type->AsShortType()->GetValue())); + break; + } + case TypeFlag::INT: { + result = CreateIntType(~(type->AsIntType()->GetValue())); + break; + } + case TypeFlag::LONG: { + result = CreateLongType(~(type->AsLongType()->GetValue())); + break; + } + default: { + UNREACHABLE(); + } + } + + node->SetTsType(result); + return result; +} + +Type *STSChecker::HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::STS_NUMERIC) && + right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::STS_NUMERIC)); + + if (left->IsDoubleType() || right->IsDoubleType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + if (left->IsFloatType() || right->IsFloatType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + if (left->IsLongType() || right->IsLongType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + return PerformRelationOperationOnTypes(left, right, operationType); +} + +std::tuple STSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right, + lexer::TokenType operationType, lexer::SourcePosition pos) +{ + checker::Type *leftType = left->Check(this); + checker::Type *rightType = right->Check(this); + checker::Type *tsType {}; + + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::STS_NUMERIC); + + if (!promotedType && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + if (leftType->IsSTSStringType() || rightType->IsSTSStringType()) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + [[fallthrough]]; + } + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + if (leftType->IsSTSStringType() || rightType->IsSTSStringType()) { + tsType = HandleStringConcatenation(leftType, rightType); + break; + } + + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::STS_NUMERIC); + + if (!promotedType && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type or String.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + leftType = ApplyUnaryOperatorPromotion(leftType, false); + rightType = ApplyUnaryOperatorPromotion(rightType, false); + + if (!leftType->HasTypeFlag(checker::TypeFlag::STS_INTEGRAL) || + !rightType->HasTypeFlag(checker::TypeFlag::STS_INTEGRAL)) { + ThrowTypeError("Bad operand type, the types of the operands must be intergral type.", pos); + } + + if (leftType->HasTypeFlag(TypeFlag::CONSTANT) && rightType->HasTypeFlag(TypeFlag::CONSTANT)) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = leftType; + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { + if (leftType->IsSTSBooleanType() && rightType->IsSTSBooleanType()) { + tsType = HandleBooleanLogicalOperators(leftType, rightType, operationType); + break; + } + + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::STS_INTEGRAL); + + if (!promotedType && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be intergral type.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + if (!leftType->HasTypeFlag(checker::TypeFlag::STS_BOOLEAN) || + !rightType->HasTypeFlag(checker::TypeFlag::STS_BOOLEAN)) { + ThrowTypeError("Bad operand type, the types of the operands must be boolean type.", pos); + } + + tsType = HandleBooleanLogicalOperators(leftType, rightType, operationType); + break; + } + + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + if ((leftType->IsSTSObjectType() && rightType->IsSTSObjectType()) || + (leftType->IsSTSStringType() && rightType->IsSTSStringType())) { + tsType = GlobalSTSBooleanType(); + auto *opType = GlobalSTSObjectType(); + return {tsType, opType}; + } + + if (leftType->IsSTSBooleanType() && rightType->IsSTSBooleanType()) { + if (leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) && + rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + bool res = leftType->AsSTSBooleanType()->GetValue() == rightType->AsSTSBooleanType()->GetValue(); + + tsType = CreateSTSBooleanType(operationType == lexer::TokenType::PUNCTUATOR_EQUAL ? res : !res); + break; + } + + tsType = GlobalSTSBooleanType(); + break; + } + + [[fallthrough]]; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::STS_NUMERIC); + + if (!promotedType && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + if (bothConst) { + tsType = HandleRelationOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = GlobalSTSBooleanType(); + auto *opType = promotedType; + return {tsType, opType}; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + if (!leftType->HasTypeFlag(checker::TypeFlag::STS_OBJECT) || + !rightType->HasTypeFlag(checker::TypeFlag::STS_OBJECT)) { + ThrowTypeError("Bad operand type, the types of the operands must be same type.", pos); + } + + tsType = GlobalSTSBooleanType(); + break; + } + default: { + // TODO + UNREACHABLE(); + break; + } + } + + return {tsType, tsType}; +} + +Type *STSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::STS_NUMERIC) && + right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::STS_NUMERIC)); + + if (left->IsDoubleType() || right->IsDoubleType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + if (left->IsFloatType() || right->IsFloatType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + if (left->IsLongType() || right->IsLongType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + return PerformArithmeticOperationOnTypes(left, right, operationType); +} + +} // namespace panda::es2panda::checker diff --git a/checker/sts/arithmetic.h b/checker/sts/arithmetic.h new file mode 100644 index 000000000..a8b396743 --- /dev/null +++ b/checker/sts/arithmetic.h @@ -0,0 +1,217 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_ARITHMETIC_H +#define ES2PANDA_COMPILER_CHECKER_STS_ARITHMETIC_H + +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/stsBooleanType.h" + +namespace panda::es2panda::checker { + +template +typename TargetType::UType STSChecker::GetOperand(Type *type) +{ + switch (STSType(type)) { + case TypeFlag::BYTE: { + return type->AsByteType()->GetValue(); + } + case TypeFlag::CHAR: { + return type->AsCharType()->GetValue(); + } + case TypeFlag::SHORT: { + return type->AsShortType()->GetValue(); + } + case TypeFlag::INT: { + return type->AsIntType()->GetValue(); + } + case TypeFlag::LONG: { + return type->AsLongType()->GetValue(); + } + case TypeFlag::FLOAT: { + return type->AsFloatType()->GetValue(); + } + case TypeFlag::DOUBLE: { + return type->AsDoubleType()->GetValue(); + } + default: { + UNREACHABLE(); + } + } +} + +template +Type *STSChecker::PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + using UType = typename TargetType::UType; + + UType leftValue = GetOperand(left); + UType rightValue = GetOperand(right); + + bool result {}; + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + result = leftValue < rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + result = leftValue <= rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + result = leftValue > rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + result = leftValue >= rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_EQUAL: { + result = leftValue == rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + result = leftValue != rightValue; + break; + } + default: { + UNREACHABLE(); + } + } + + return CreateSTSBooleanType(result); +} + +template +Type *STSChecker::PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + using UType = typename TargetType::UType; + + UType leftValue = GetOperand(left); + UType rightValue = GetOperand(right); + auto result = leftValue; + + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + result = leftValue + rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + result = leftValue - rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { + result = leftValue / rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { + result = leftValue * rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + result = HandleModulo(leftValue, rightValue); + break; + } + default: { + result = HandleBitWiseArithmetic(leftValue, rightValue, operationType); + } + } + + return allocator_.New(result); +} + +template <> +inline IntType::UType panda::es2panda::checker::STSChecker::HandleModulo(IntType::UType leftValue, + IntType::UType rightValue) +{ + return leftValue % rightValue; +} + +template <> +inline LongType::UType panda::es2panda::checker::STSChecker::HandleModulo(LongType::UType leftValue, + LongType::UType rightValue) +{ + return leftValue % rightValue; +} + +template <> +inline FloatType::UType panda::es2panda::checker::STSChecker::HandleModulo( + FloatType::UType leftValue, FloatType::UType rightValue) +{ + return std::fmod(leftValue, rightValue); +} + +template <> +inline DoubleType::UType panda::es2panda::checker::STSChecker::HandleModulo( + DoubleType::UType leftValue, DoubleType::UType rightValue) +{ + return std::fmod(leftValue, rightValue); +} + +template +UType STSChecker::HandleBitWiseArithmetic(UType leftValue, UType rightValue, lexer::TokenType operationType) +{ + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { + return leftValue & rightValue; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { + return leftValue | rightValue; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { + return leftValue ^ rightValue; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { + return leftValue << rightValue; + } + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + return leftValue >> rightValue; + } + default: { + UNREACHABLE(); + } + } +} + +template <> +inline FloatType::UType STSChecker::HandleBitWiseArithmetic( + [[maybe_unused]] FloatType::UType leftValue, [[maybe_unused]] FloatType::UType rightValue, + [[maybe_unused]] lexer::TokenType operationType) +{ + return 0.0; +} + +template <> +inline DoubleType::UType STSChecker::HandleBitWiseArithmetic( + [[maybe_unused]] DoubleType::UType leftValue, [[maybe_unused]] DoubleType::UType rightValue, + [[maybe_unused]] lexer::TokenType operationType) +{ + return 0.0; +} +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/sts/baseAnalyzer.cpp b/checker/sts/baseAnalyzer.cpp new file mode 100644 index 000000000..47fcdeabb --- /dev/null +++ b/checker/sts/baseAnalyzer.cpp @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "baseAnalyzer.h" +#include "plugins/ecmascript/es2panda/ir/astNode.h" +#include "plugins/ecmascript/es2panda/ir/statements/breakStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/continueStatement.h" + +namespace panda::es2panda::checker { + +const ir::AstNode *BaseAnalyzer::GetJumpTarget(const ir::AstNode *node) const +{ + if (node->IsBreakStatement()) { + return node->AsBreakStatement()->Target(); + } + + ASSERT(node->IsContinueStatement()); + return node->AsContinueStatement()->Target(); +} + +LivenessStatus BaseAnalyzer::ResolveJump(const ir::AstNode *node, PendingExitsVector &oldPendingExits, + ir::AstNodeType jumpKind) +{ + bool resolved = false; + + for (auto &it : pendingExits_) { + if (it.Node()->Type() == jumpKind && node == GetJumpTarget(it.Node())) { + it.ResolveJump(); + resolved = true; + } else { + oldPendingExits.push_back(it); + } + } + + pendingExits_.swap(oldPendingExits); + return From(resolved); +} + +LivenessStatus BaseAnalyzer::ResolveContinues(const ir::AstNode *node) +{ + PendingExitsVector oldPendingExits; + return ResolveJump(node, oldPendingExits, ir::AstNodeType::CONTINUE_STATEMENT); +} + +LivenessStatus BaseAnalyzer::ResolveBreaks(const ir::AstNode *node, PendingExitsVector &oldPendingExits) +{ + return ResolveJump(node, oldPendingExits, ir::AstNodeType::BREAK_STATEMENT); +} + +} // namespace panda::es2panda::checker diff --git a/checker/sts/baseAnalyzer.h b/checker/sts/baseAnalyzer.h new file mode 100644 index 000000000..005819cbf --- /dev/null +++ b/checker/sts/baseAnalyzer.h @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_BASE_ANALYZER_H +#define ES2PANDA_COMPILER_CHECKER_STS_BASE_ANALYZER_H + +#include "utils/arena_containers.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +namespace panda::es2panda::ir { +class AstNode; +enum class AstNodeType; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class STSChecker; + +enum class LivenessStatus { DEAD, ALIVE }; + +DEFINE_BITOPS(LivenessStatus) + +class PendingExit { +public: + using JumpResolver = std::function; + + explicit PendingExit( + const ir::AstNode *node, const JumpResolver &jumpResolver = [] {}) + : node_(node), jumpResolver_(jumpResolver) + { + } + ~PendingExit() = default; + + DEFAULT_COPY_SEMANTIC(PendingExit); + DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PendingExit); + + void ResolveJump() const + { + jumpResolver_(); + } + + const ir::AstNode *Node() const + { + return node_; + } + +private: + const ir::AstNode *node_; + JumpResolver jumpResolver_; +}; + +using PendingExitsVector = std::vector; + +class BaseAnalyzer { +public: + explicit BaseAnalyzer() {} + + virtual void MarkDead() = 0; + + void RecordExit(PendingExit pe) + { + pendingExits_.push_back(pe); + MarkDead(); + } + + LivenessStatus From(bool value) + { + return value ? LivenessStatus::ALIVE : LivenessStatus::DEAD; + } + + LivenessStatus ResolveJump(const ir::AstNode *node, PendingExitsVector &oldPendingExits, ir::AstNodeType jumpKind); + LivenessStatus ResolveContinues(const ir::AstNode *node); + LivenessStatus ResolveBreaks(const ir::AstNode *node, PendingExitsVector &oldPendingExits); + const ir::AstNode *GetJumpTarget(const ir::AstNode *node) const; + +protected: + PendingExitsVector pendingExits_; +}; +} // namespace panda::es2panda::checker +#endif diff --git a/checker/sts/boxingConverter.cpp b/checker/sts/boxingConverter.cpp new file mode 100644 index 000000000..4126d062b --- /dev/null +++ b/checker/sts/boxingConverter.cpp @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/checker/sts/primitiveWrappers.h" + +namespace panda::es2panda::checker { + +void BoxingConverter::STSTypeFromSource(Type *source) +{ + auto typeKind = checker::STSChecker::TypeKind(source); + + auto wrapMap = checker_->PrimitiveWrapper(); + + switch (typeKind) { + case checker::TypeFlag::BOOLEAN: { + auto res = wrapMap.find("Boolean"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::BYTE: { + auto res = wrapMap.find("Byte"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::SHORT: { + auto res = wrapMap.find("Short"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::CHAR: { + auto res = wrapMap.find("Char"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::INT: { + auto res = wrapMap.find("Int"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::LONG: { + auto res = wrapMap.find("Long"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::FLOAT: { + auto res = wrapMap.find("Float"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::DOUBLE: { + auto res = wrapMap.find("Double"); + result_ = res->second.first; + break; + } + default: + break; + } +} + +} // namespace panda::es2panda::checker \ No newline at end of file diff --git a/checker/sts/boxingConverter.h b/checker/sts/boxingConverter.h new file mode 100644 index 000000000..1195733bd --- /dev/null +++ b/checker/sts/boxingConverter.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_BOXING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_STS_BOXING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/stsObjectType.h" + +namespace panda::es2panda::checker { +class BoxingConverter : public TypeConverter { +public: + BoxingConverter(STSChecker *checker, TypeRelation *relation, Type *source, Type *target) + : TypeConverter(checker, relation, target, source) + { + ASSERT(relation->GetNode()); + + if (!target->IsSTSObjectType()) { + return; + } + + STSTypeFromSource(source); + } + + void STSTypeFromSource(Type *source); + +private: + STSObjectType *result_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/sts/function.cpp b/checker/sts/function.cpp new file mode 100644 index 000000000..50310d45f --- /dev/null +++ b/checker/sts/function.cpp @@ -0,0 +1,487 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/checker/sts/typeRelationContext.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { + +bool STSChecker::ValidateSignature(Signature *signature, const ArenaVector &arguments, + const lexer::SourcePosition &pos, TypeRelationFlag initialFlags) +{ + if ((arguments.size() < signature->MinArgCount()) || + (arguments.size() > signature->MinArgCount() && !signature->RestVar())) { + if (!(initialFlags & TypeRelationFlag::NO_THROW)) { + ThrowTypeError({"Expected ", signature->MinArgCount(), " arguments, got ", arguments.size(), " ."}, pos); + } + + return false; + } + + uint32_t index = 0; + bool validateRest = false; + + for (; index < arguments.size(); index++) { + if (index >= signature->MinArgCount()) { + ASSERT(signature->RestVar()); + validateRest = true; + break; + } + + Type *argType = arguments[index]->Check(this); + auto invocationtCtx = checker::InvocationContext( + relation_, arguments[index], argType, signature->Params()[index]->TsType(), arguments[index]->Start(), + {"Call argument at index ", index, " is not compatible with the signature's type at that index"}, + initialFlags); + + if (!invocationtCtx.IsInvocable()) { + return false; + } + } + + if ((initialFlags & TypeRelationFlag::SELF_REFERENCE) && (!signature->Function()->IsStatic()) && + (HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) && !signature->Function()->IsConstructor()) { + return false; + } + + if (!validateRest) { + return true; + } + + do { + Type *argType = arguments[index]->Check(this); + auto invocationtCtx = checker::InvocationContext( + relation_, arguments[index], argType, signature->RestVar()->TsType(), arguments[index]->Start(), + {"Call argument at index ", index, " is not compatible with the signature's rest parameter type"}, + initialFlags); + index++; + + if (!invocationtCtx.IsInvocable()) { + return false; + } + } while (index < arguments.size()); + + return true; +} + +Signature *STSChecker::ValidateSignatures(ArenaVector &signatures, + const ArenaVector &arguments, + const lexer::SourcePosition &pos, std::string_view signatureKind, + TypeRelationFlag flags) +{ + for (auto *sig : signatures) { + if (ValidateSignature(sig, arguments, pos, flags | TypeRelationFlag::NO_THROW)) { + return sig; + } + } + + if (flags & TypeRelationFlag::WIDENING) { + ThrowTypeError({"No matching ", signatureKind, " signature"}, pos); + } + + return nullptr; +} + +Signature *STSChecker::ResolveCallExpression(ArenaVector &signatures, + const ArenaVector &arguments, + const lexer::SourcePosition &pos, bool isIdentifier) +{ + auto flag = isIdentifier ? TypeRelationFlag::SELF_REFERENCE : TypeRelationFlag::NONE; + + auto *sig = ValidateSignatures(signatures, arguments, pos, "call", flag); + + if (sig) { + return sig; + } + + return ValidateSignatures(signatures, arguments, pos, "call", flag | TypeRelationFlag::WIDENING); +} + +Signature *STSChecker::ResolveConstructExpression(STSObjectType *type, const ArenaVector &arguments, + const lexer::SourcePosition &pos) +{ + auto *sig = ValidateSignatures(type->ConstructSignatures(), arguments, pos, "construct", TypeRelationFlag::NONE); + + if (sig) { + return sig; + } + + return ValidateSignatures(type->ConstructSignatures(), arguments, pos, "construct", TypeRelationFlag::WIDENING); +} + +checker::STSFunctionType *STSChecker::BuildMethodSignature(ir::MethodDefinition *method) +{ + if (method->TsType()) { + return method->TsType()->AsSTSFunctionType(); + } + + bool isConstructSig = method->IsConstructor(); + + auto *funcType = BuildFunctionSignature(method->Function(), isConstructSig); + + auto overloadList = method->Overloads(); + + for (size_t baseFuncCounter = 0; baseFuncCounter < overloadList.size(); baseFuncCounter++) { + auto *currentFunc = overloadList.at(baseFuncCounter); + auto *overloadType = BuildFunctionSignature(currentFunc->Function(), isConstructSig); + CheckIdenticalOverloads(funcType, overloadType, currentFunc->Start()); + for (size_t compareFuncCounter = baseFuncCounter + 1; compareFuncCounter < overloadList.size(); + compareFuncCounter++) { + auto *compareFunc = overloadList.at(compareFuncCounter); + auto *compareOverloadType = BuildFunctionSignature(compareFunc->Function(), isConstructSig); + CheckIdenticalOverloads(overloadType, compareOverloadType, compareFunc->Start()); + } + currentFunc->SetTsType(overloadType); + funcType->AddCallSignature(currentFunc->Function()->Signature()); + } + + method->Id()->Variable()->SetTsType(funcType); + return funcType; +} + +void STSChecker::CheckIdenticalOverloads(STSFunctionType *func, STSFunctionType *overload, + const lexer::SourcePosition &overloadStart) +{ + SavedTypeRelationFlagsContext savedFlagsCtx(relation_, TypeRelationFlag::NO_RETURN_TYPE_CHECK); + relation_->IsIdenticalTo(func, overload); + if (relation_->IsTrue()) { + ThrowTypeError("Function already declared.", overloadStart); + } +} + +checker::STSFunctionType *STSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig) +{ + auto *nameVar = func->Id()->Variable(); + + auto *signatureInfo = CreateSignatureInfo(); + signatureInfo->restVar = nullptr; + signatureInfo->minArgCount = 0; + + if ((func->IsConstructor() || !func->IsStatic()) && + !context_.ContainingClass()->HasObjectFlag(STSObjectFlags::INTERFACE)) { + auto *thisVar = func->Scope()->ParamScope()->Params().front(); + thisVar->SetTsType(context_.ContainingClass()); + } + + for (auto *it : func->Params()) { + if (it->IsRestElement()) { + auto *restParam = it->AsRestElement(); + ASSERT(restParam->Argument()->IsIdentifier()); + + auto *restIdent = restParam->Argument()->AsIdentifier(); + + ASSERT(restIdent->Variable()); + signatureInfo->restVar = restIdent->Variable()->AsLocalVariable(); + + ASSERT(restParam->TypeAnnotation()); + signatureInfo->restVar->SetTsType(restParam->TypeAnnotation()->GetType(this)); + break; + } + + ASSERT(it->IsIdentifier()); + auto *paramIdent = it->AsIdentifier(); + + ASSERT(paramIdent->Variable()); + binder::Variable *paramVar = paramIdent->Variable(); + + ASSERT(paramIdent->TypeAnnotation()); + paramVar->SetTsType(paramIdent->TypeAnnotation()->GetType(this)); + signatureInfo->params.push_back(paramVar->AsLocalVariable()); + signatureInfo->minArgCount++; + } + + auto *returnTypeAnnotation = func->ReturnTypeAnnotation(); + checker::Type *returnType {}; + + ASSERT(returnTypeAnnotation || func->IsConstructor() || func->IsStaticBlock()); + + if (returnTypeAnnotation) { + returnType = returnTypeAnnotation->GetType(this); + returnTypeAnnotation->SetTsType(returnType); + } else { + returnType = GlobalVoidType(); + } + + auto *signature = CreateSignature(signatureInfo, returnType, func); + signature->SetOwner(context_.ContainingClass()); + + if (isConstructSig) { + signature->AddSignatureFlag(SignatureFlags::CONSTRUCT); + } else { + signature->AddSignatureFlag(SignatureFlags::CALL); + } + + auto *funcType = CreateSTSFunctionType(signature); + func->SetSignature(signature); + funcType->SetVariable(nameVar); + + if (func->IsAbstract()) { + signature->AddSignatureFlag(SignatureFlags::ABSTRACT); + signature->AddSignatureFlag(SignatureFlags::VIRTUAL); + } + + if (func->IsStatic()) { + signature->AddSignatureFlag(SignatureFlags::STATIC); + } + + if (func->IsOpen()) { + if (!(func->Signature()->Owner()->GetDeclNode()->IsOpen() || + func->Signature()->Owner()->HasObjectFlag(checker::STSObjectFlags::ABSTRACT))) { + ThrowTypeError("Only open or abstract classes can have open method", func->Start()); + } + signature->AddSignatureFlag(SignatureFlags::OPEN); + signature->AddSignatureFlag(SignatureFlags::PUBLIC); + } + + if (func->IsPublic()) { + signature->AddSignatureFlag(SignatureFlags::PUBLIC); + } else if (func->IsProtected()) { + signature->AddSignatureFlag(SignatureFlags::PROTECTED); + } else if (func->IsPrivate()) { + signature->AddSignatureFlag(SignatureFlags::PRIVATE); + } + + nameVar->SetTsType(funcType); + + return funcType; +} + +Signature *STSChecker::CheckEveryAbstractSignatureIsOverriden(STSFunctionType *target, STSFunctionType *source) +{ + for (auto targetSig = target->CallSignatures().begin(); targetSig != target->CallSignatures().end();) { + if (!(*targetSig)->HasSignatureFlag(SignatureFlags::ABSTRACT)) { + continue; + } + + bool isOverridden = false; + for (auto sourceSig : source->CallSignatures()) { + relation_->IsIdenticalTo(*targetSig, sourceSig); + if (relation_->IsTrue() && (*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name()) { + target->CallSignatures().erase(targetSig); + isOverridden = true; + break; + } + sourceSig++; + } + + if (!isOverridden) { + return *targetSig; + } + } + + return nullptr; +} + +bool STSChecker::IsOverridableIn(Signature *signature) +{ + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + return false; + } + + if (signature->HasSignatureFlag(SignatureFlags::PUBLIC)) { + return !FindAncestorGivenByType(signature->Function(), ir::AstNodeType::TS_INTERFACE_DECLARATION) || + signature->HasSignatureFlag(SignatureFlags::STATIC); + } + + if (signature->HasSignatureFlag(SignatureFlags::PROTECTED)) { + return true; + } + + return false; +} + +bool STSChecker::IsMethodOverridesOther(Signature *target, Signature *source) +{ + if (source->Function()->IsConstructor()) { + return false; + } + + if (target == source) { + return true; + } + + if (IsOverridableIn(target)) { + SavedTypeRelationFlagsContext savedFlagsCtx(relation_, TypeRelationFlag::NO_RETURN_TYPE_CHECK); + relation_->IsIdenticalTo(target, source); + if (relation_->IsTrue()) { + if (!source->Function()->IsOverride()) { + ThrowTypeError("Method overriding requires 'override' modifier", source->Function()->Start()); + } + return true; + } + } + + return false; +} + +std::tuple STSChecker::CheckOverride(Signature *signature, Signature *other) +{ + if (signature->HasSignatureFlag(SignatureFlags::STATIC) != other->HasSignatureFlag(SignatureFlags::STATIC)) { + return {false, OverrideErrorCode::OVERRIDING_STATIC}; + } + + if (!(other->HasSignatureFlag(SignatureFlags::OPEN) || other->Function()->IsOverride())) { + return {false, OverrideErrorCode::OVERRIDEN_NOT_OPEN}; + } + + if (!IsTypeAssignableTo(signature->ReturnType(), other->ReturnType())) { + return {false, OverrideErrorCode::INCOMPATIBLE_RETURN}; + } + + if (signature->ProtectionFlag() > other->ProtectionFlag()) { + return {false, OverrideErrorCode::OVERRIDEN_WEAKER}; + } + + return {true, OverrideErrorCode::NO_ERROR}; +} + +bool STSChecker::CheckOverride(Signature *signature, STSObjectType *site) +{ + auto *target = site->GetProperty(signature->Function()->Id()->Name(), PropertySearchFlags::NO_OPTS); + bool isOverridingAnySignature = false; + + if (!target || !target->TsType()->IsSTSFunctionType()) { + return isOverridingAnySignature; + } + + for (auto *it : target->TsType()->AsSTSFunctionType()->CallSignatures()) { + if (it->HasSignatureFlag(SignatureFlags::ABSTRACT) || site->HasObjectFlag(STSObjectFlags::INTERFACE)) { + isOverridingAnySignature = true; + continue; + } + + if (!IsMethodOverridesOther(it, signature)) { + continue; + } + + auto [success, errorCode] = CheckOverride(signature, it); + + if (!success) { + const char *reason {}; + switch (errorCode) { + case OverrideErrorCode::OVERRIDING_STATIC: { + reason = "overriding method is static."; + break; + } + case OverrideErrorCode::OVERRIDEN_STATIC: { + reason = "overriden method is static."; + break; + } + case OverrideErrorCode::OVERRIDEN_NOT_OPEN: { + reason = "overriden method is not open."; + break; + } + case OverrideErrorCode::INCOMPATIBLE_RETURN: { + reason = "overriding return type is not compatible with the other return type."; + break; + } + case OverrideErrorCode::OVERRIDEN_WEAKER: { + reason = "overriden method has weaker access privilage."; + break; + } + default: { + UNREACHABLE(); + } + } + + ThrowTypeError({signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), + " cannot override ", it->Function()->Id()->Name(), it, " in ", it->Owner(), " because ", + reason}, + signature->Function()->Start()); + } + + isOverridingAnySignature = true; + it->AddSignatureFlag(SignatureFlags::VIRTUAL); + signature->AddSignatureFlag(SignatureFlags::OPEN); + } + + return isOverridingAnySignature; +} + +void STSChecker::CheckOverride(Signature *signature) +{ + auto *owner = signature->Owner(); + bool isOverriding = false; + + if (!owner->HasObjectFlag(STSObjectFlags::CLASS)) { + return; + } + + STSObjectType *iter = owner->SuperType(); + + for (auto *it : owner->Interfaces()) { + isOverriding |= CheckOverride(signature, it); + } + + while (iter) { + isOverriding |= CheckOverride(signature, iter); + + for (auto *it : iter->Interfaces()) { + isOverriding |= CheckOverride(signature, it); + } + + iter = iter->SuperType(); + } + + if (!isOverriding && signature->Function()->IsOverride()) { + ThrowTypeError({"Method ", signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), + " not overriding any method"}, + signature->Function()->Start()); + } +} + +Signature *STSChecker::GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef) +{ + ASSERT(methodDef->TsType() && methodDef->TsType()->IsSTSFunctionType()); + + for (auto *it : methodDef->TsType()->AsSTSFunctionType()->CallSignatures()) { + if (it->Function() == methodDef->Function()) { + return it; + } + } + + return nullptr; +} + +void STSChecker::ValidateSignatureAccessibility(STSObjectType *callee, Signature *signature, + const lexer::SourcePosition &pos) +{ + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + if (context_.ContainingClass() == callee && callee->IsSignatureInherited(signature)) { + return; + } + + auto *currentOutermost = context_.ContainingClass()->OutermostClass(); + auto *objOutermost = callee->OutermostClass(); + + if (currentOutermost && objOutermost && currentOutermost == objOutermost && + callee->IsSignatureInherited(signature)) { + return; + } + + ThrowTypeError({"Signature ", signature->Function()->Id()->Name(), signature, " is not visible here."}, pos); + } +} +} // namespace panda::es2panda::checker diff --git a/checker/sts/helpers.cpp b/checker/sts/helpers.cpp new file mode 100644 index 000000000..8681e7eb5 --- /dev/null +++ b/checker/sts/helpers.cpp @@ -0,0 +1,624 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/checker/sts/typeRelationContext.h" +#include "plugins/ecmascript/es2panda/checker/sts/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" + +namespace panda::es2panda::checker { +void STSChecker::CheckTruthinessOfType(Type *type, const lexer::SourcePosition &pos) +{ + if (!type->IsSTSBooleanType()) { + ThrowTypeError("Condition must be of type boolean", pos); + } +} + +Type *STSChecker::GetDefaultTypeFromPrimitiveType(Type *type) +{ + if (!type->HasTypeFlag(TypeFlag::STS_PRIMITIVE)) { + return type; + } + + if (type->HasTypeFlag(TypeFlag::STS_INTEGRAL)) { + return GlobalIntType(); + } + + if (type->HasTypeFlag(TypeFlag::FLOAT | TypeFlag::DOUBLE)) { + return GlobalDoubleType(); + } + + if (type->IsSTSBooleanType()) { + return GlobalSTSBooleanType(); + } + return type; +} + +bool STSChecker::IsConstantExpression(ir::Expression *expr, Type *type) +{ + return (type->HasTypeFlag(TypeFlag::CONSTANT) && (expr->IsIdentifier() || expr->IsMemberExpression())); +} + +Type *STSChecker::GetTypeOfVariable(binder::Variable *var) +{ + if (var->TsType()) { + return var->TsType(); + } + + binder::Decl *decl = var->Declaration(); + + switch (decl->Type()) { + case binder::DeclType::CLASS: { + auto *classDef = decl->Node()->AsClassDefinition(); + BuildClassProperties(classDef); + return classDef->TsType(); + } + case binder::DeclType::CONST: + case binder::DeclType::VAR: { + auto *declNode = decl->Node(); + + if (decl->Node()->IsIdentifier()) { + declNode = declNode->Parent(); + } + + return declNode->Check(this); + } + case binder::DeclType::FUNC: { + return decl->Node()->Check(this); + } + default: { + UNREACHABLE(); + } + } + + return var->TsType(); +} + +void STSChecker::ValidatePropertyAccess(binder::Variable *var, STSObjectType *obj, const lexer::SourcePosition &pos) +{ + if (!var->HasFlag(binder::VariableFlags::STATIC) && HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) { + ThrowTypeError("non-static variable cannot be referenced from a static context", pos); + } + + if (var->HasFlag(binder::VariableFlags::PRIVATE)) { + if (context_.ContainingClass() == obj && obj->IsPropertyInherited(var)) { + return; + } + + auto *currentOutermost = context_.ContainingClass()->OutermostClass(); + auto *objOutermost = obj->OutermostClass(); + + if (currentOutermost && objOutermost && currentOutermost == objOutermost && obj->IsPropertyInherited(var)) { + return; + } + + ThrowTypeError({"Property ", var->Name(), " is not visible here."}, pos); + } +} + +Type *STSChecker::ResolveIdentifier(ir::Identifier *ident) +{ + if (ident->Variable()) { + if (ident->Variable()->Declaration()->Node()->IsClassProperty() && + !ident->Variable()->HasFlag(binder::VariableFlags::STATIC) && HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) { + ThrowTypeError("non-static variable cannot be referenced from a static context", ident->Start()); + } + + return GetTypeOfVariable(ident->Variable()); + } + + STSObjectType *classType = context_.ContainingClass(); + + if (!classType->SuperType() && classType->Interfaces().empty()) { + ThrowTypeError({"Cannot find variable '", ident->Name(), "'."}, ident->Start()); + } + + binder::Variable *resolved = classType->GetProperty(ident->Name(), PropertySearchFlags::SEARCH_ALL); + + if (!resolved) { + ThrowTypeError({"Cannot find variable '", ident->Name(), "'."}, ident->Start()); + } + + ValidatePropertyAccess(resolved, context_.ContainingClass(), ident->Start()); + ident->SetVariable(resolved); + return GetTypeOfVariable(ident->Variable()); +} + +void STSChecker::ValidateUnaryOperatorOperand(binder::Variable *variable) +{ + if (variable->Declaration()->IsConstDecl()) { + if (HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK) && + !variable->HasFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED)) { + ThrowTypeError({"Cannot reassign constant field ", variable->Name()}, + variable->Declaration()->Node()->Start()); + } + if (!HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK)) { + ThrowTypeError({"Cannot assign to a constant variable ", variable->Name()}, + variable->Declaration()->Node()->Start()); + } + } else if (!variable->Declaration()->IsLetDecl()) { + ThrowTypeError("Only variables can be assigned.", variable->Declaration()->Node()->Start()); + } +} + +std::tuple STSChecker::ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test) +{ + UnboxingConverter convL = UnboxingConverter(this, relation_, left, nullptr); + UnboxingConverter convR = UnboxingConverter(this, relation_, right, nullptr); + Type *unboxedL = convL.Result(); + Type *unboxedR = convR.Result(); + + if (!unboxedL->HasTypeFlag(test) || !unboxedR->HasTypeFlag(test)) { + return {nullptr, false}; + } + + if (unboxedL->HasTypeFlag(TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(TypeFlag::CONSTANT)) { + return {nullptr, true}; + } + + if (unboxedL->HasTypeFlag(TypeFlag::STS_NUMERIC) && unboxedR->HasTypeFlag(TypeFlag::STS_NUMERIC)) { + if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) { + return {GlobalDoubleType(), false}; + } + + if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) { + return {GlobalFloatType(), false}; + } + + if (unboxedL->IsLongType() || unboxedR->IsLongType()) { + return {GlobalLongType(), false}; + } + + return {GlobalIntType(), false}; + } + + if (IsTypeIdenticalTo(unboxedL, unboxedR)) { + return {unboxedL, false}; + } + + return {globalBuiltinObjectType_, false}; +} + +Type *STSChecker::ApplyUnaryOperatorPromotion(Type *type, bool createConst) +{ + UnboxingConverter conv = UnboxingConverter(this, relation_, type, nullptr); + switch (STSType(conv.Result())) { + case TypeFlag::BYTE: + case TypeFlag::SHORT: + case TypeFlag::CHAR: { + if (!createConst) { + return GlobalIntType(); + } + + return CreateIntTypeFromType(conv.Result()); + } + default: { + return conv.Result(); + } + } +} + +Type *STSChecker::HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType) +{ + using UType = typename STSBooleanType::UType; + ASSERT(leftType->IsSTSBooleanType() && rightType->IsSTSBooleanType()); + + if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return GlobalSTSBooleanType(); + } + + UType leftValue = leftType->AsSTSBooleanType()->GetValue(); + UType rightValue = rightType->AsSTSBooleanType()->GetValue(); + + switch (tokenType) { + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { + return CreateSTSBooleanType(leftValue ^ rightValue); + } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { + return CreateSTSBooleanType(leftValue & rightValue); + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { + return CreateSTSBooleanType(leftValue | rightValue); + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + return CreateSTSBooleanType(leftValue || rightValue); + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { + return CreateSTSBooleanType(leftValue && rightValue); + } + default: { + break; + } + } + + UNREACHABLE(); + return nullptr; +} + +checker::Type *STSChecker::CheckVariableDeclaration(checker::STSChecker *checker, ir::Identifier *ident, + ir::TypeNode *typeAnnotation, ir::Expression *init, + ir::ModifierFlags flags) +{ + const util::StringView &varName = ident->Name(); + ASSERT(ident->Variable()); + binder::Variable *bindingVar = ident->Variable(); + checker::Type *annotationType = nullptr; + + bool isConst = flags & ir::ModifierFlags::CONST; + + if (typeAnnotation) { + annotationType = typeAnnotation->GetType(checker); + bindingVar->SetTsType(annotationType); + } + + if (!init) { + return annotationType; + } + + checker::Type *initType = init->Check(checker); + + if (annotationType) { + AssignmentContext(checker->Relation(), init, initType, annotationType, init->Start(), + {"Initializers type is not assignable to the target type"}); + if (isConst && initType->HasTypeFlag(TypeFlag::STS_PRIMITIVE)) { + bindingVar->SetTsType(init->TsType()); + } + } else if (!annotationType) { + bindingVar->SetTsType(isConst ? initType : checker->GetDefaultTypeFromPrimitiveType(initType)); + + if (bindingVar->TsType()->IsSTSNullType()) { + checker->ThrowTypeError({"Cannot infer type for variable '", varName, "'."}, init->Start()); + } + } + + return bindingVar->TsType(); +} + +Type *STSChecker::GetTypeFromInterfaceReference(binder::Variable *var) +{ + if (var->TsType()) { + return var->TsType(); + } + + auto *interfaceType = BuildInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration()); + var->SetTsType(interfaceType); + return interfaceType; +} + +Type *STSChecker::GetTypeFromClassReference(binder::Variable *var) +{ + if (var->TsType()) { + return var->TsType(); + } + + auto *classType = BuildClassProperties(var->Declaration()->Node()->AsClassDefinition()); + var->SetTsType(classType); + return classType; +} + +Type *STSChecker::GetTypeFromEnumReference([[maybe_unused]] binder::Variable *var) +{ + // TODO + return nullptr; +} + +Type *STSChecker::GetTypeFromTypeParameterReference(binder::LocalVariable *var, const lexer::SourcePosition &pos) +{ + if (HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) { + ThrowTypeError({"Cannot make a static reference to the non-static type ", var->Name()}, pos); + } + + auto *typeParam = var->TsType()->AsSTSTypeParameter(); + return CreateTypeReference(typeParam->GetTypeRef(), typeParam->GetAssemblerTypeRef(), var); +} + +Type *STSChecker::GetReferencedTypeFromBase([[maybe_unused]] Type *baseType, [[maybe_unused]] ir::Expression *name) +{ + // TODO + return nullptr; +} + +Type *STSChecker::GetReferencedTypeBase(ir::Expression *name) +{ + if (name->IsTSQualifiedName()) { + // TODO + return nullptr; + } + + ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable()); + auto *refVar = name->AsIdentifier()->Variable()->AsLocalVariable(); + + switch (refVar->Declaration()->Node()->Type()) { + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + return GetTypeFromInterfaceReference(refVar); + } + case ir::AstNodeType::CLASS_DECLARATION: + case ir::AstNodeType::CLASS_DEFINITION: { + return GetTypeFromClassReference(refVar); + } + case ir::AstNodeType::TS_ENUM_DECLARATION: { + return GetTypeFromEnumReference(refVar); + } + case ir::AstNodeType::TS_TYPE_PARAMETER: { + return GetTypeFromTypeParameterReference(refVar, name->Start()); + } + default: { + UNREACHABLE(); + } + } +} + +void STSChecker::ConcantConstantString(util::UString &target, Type *type) +{ + switch (STSType(type)) { + case TypeFlag::STS_OBJECT: { + ASSERT(type->IsSTSStringType()); + target.Append(type->AsSTSStringType()->GetValue()); + break; + } + case TypeFlag::STS_BOOLEAN: { + STSBooleanType::UType value = type->AsSTSBooleanType()->GetValue(); + target.Append(value ? "true" : "false"); + break; + } + case TypeFlag::BYTE: { + ByteType::UType value = type->AsByteType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::CHAR: { + CharType::UType value = type->AsCharType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::SHORT: { + ShortType::UType value = type->AsShortType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::INT: { + IntType::UType value = type->AsIntType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::LONG: { + LongType::UType value = type->AsLongType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::FLOAT: { + FloatType::UType value = type->AsFloatType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::DOUBLE: { + DoubleType::UType value = type->AsDoubleType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + default: { + UNREACHABLE(); + } + } +} + +Type *STSChecker::HandleStringConcatenation(Type *leftType, Type *rightType) +{ + ASSERT(leftType->IsSTSStringType() || rightType->IsSTSStringType()); + + if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return GlobalSTSStringType(); + } + + util::UString concatenated(&allocator_); + ConcantConstantString(concatenated, leftType); + ConcantConstantString(concatenated, rightType); + + return CreateSTSStringType(concatenated.View()); +} + +STSFunctionType *STSChecker::FindFunctionInVectorGivenByName(util::StringView name, + ArenaVector &list) +{ + for (auto *it : list) { + if (it->Name() == name) { + return it; + } + } + + return nullptr; +} + +bool STSChecker::IsFunctionContainsSignature(STSFunctionType *funcType, Signature *signature) +{ + for (auto *it : funcType->CallSignatures()) { + relation_->IsIdenticalTo(it, signature); + if (relation_->IsTrue()) { + return true; + } + } + + return false; +} + +void STSChecker::CheckFunctionContainsClashingSignature(const STSFunctionType *funcType, Signature *signature) +{ + for (auto *it : funcType->CallSignatures()) { + SavedTypeRelationFlagsContext strfCtx(relation_, TypeRelationFlag::NO_RETURN_TYPE_CHECK); + relation_->IsIdenticalTo(it, signature); + if (relation_->IsTrue() && it->Function()->Id()->Name() == signature->Function()->Id()->Name()) { + std::stringstream ss; + it->ToString(ss, nullptr, true); + auto sigStr1 = ss.str(); + ss.str(std::string {}); // Clear buffer + signature->ToString(ss, nullptr, true); + auto sigStr2 = ss.str(); + ThrowTypeError({"Function '", it->Function()->Id()->Name(), sigStr1.c_str(), + "' is redeclared with different signature '", signature->Function()->Id()->Name(), + sigStr2.c_str(), "'"}, + signature->Function()->ReturnTypeAnnotation()->Start()); + } + } +} + +void STSChecker::MergeSignatures(STSFunctionType *target, STSFunctionType *source) +{ + for (auto *s : source->CallSignatures()) { + if (IsFunctionContainsSignature(target, s)) { + continue; + } + + CheckFunctionContainsClashingSignature(target, s); + target->AddCallSignature(s); + } +} + +void STSChecker::MergeComputedAbstracts(ArenaVector &merged, ArenaVector ¤t) +{ + for (auto *curr : current) { + auto name = curr->Name(); + auto *found = FindFunctionInVectorGivenByName(name, merged); + if (found) { + MergeSignatures(found, curr); + continue; + } + + merged.push_back(curr); + } +} + +ir::AstNode *STSChecker::FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type) +{ + auto *iter = node->Parent(); + + while (iter) { + if (iter->Type() == type) { + return iter; + } + + iter = iter->Parent(); + } + + return nullptr; +} + +util::StringView STSChecker::GetContainingObjectNameFromSignature(Signature *signature) +{ + ASSERT(signature->Function()); + auto *iter = signature->Function()->Parent(); + + while (iter) { + if (iter->IsClassDefinition()) { + return iter->AsClassDefinition()->Ident()->Name(); + } + + if (iter->IsTSInterfaceDeclaration()) { + return iter->AsTSInterfaceDeclaration()->Id()->Name(); + } + + iter = iter->Parent(); + } + + UNREACHABLE(); + return {""}; +} + +bool STSChecker::IsTypeBuiltinType(Type *type) +{ + if (!type->IsSTSObjectType()) { + return false; + } + + switch (type->AsSTSObjectType()->BuiltInKind()) { + case STSObjectFlags::BUILTIN_BOOLEAN: + case STSObjectFlags::BUILTIN_BYTE: + case STSObjectFlags::BUILTIN_SHORT: + case STSObjectFlags::BUILTIN_CHAR: + case STSObjectFlags::BUILTIN_INT: + case STSObjectFlags::BUILTIN_LONG: + case STSObjectFlags::BUILTIN_FLOAT: + case STSObjectFlags::BUILTIN_DOUBLE: { + return true; + } + default: + return false; + } +} + +const ir::AstNode *STSChecker::FindJumpTarget(ir::AstNodeType nodeType, const ir::AstNode *node, + const ir::Identifier *target) +{ + const auto *iter = node->Parent(); + + while (iter) { + switch (iter->Type()) { + case ir::AstNodeType::LABELLED_STATEMENT: { + const auto *labelled = iter->AsLabelledStatement(); + if (labelled->Ident() == target) { + if (nodeType == ir::AstNodeType::CONTINUE_STATEMENT) { + return labelled->GetReferencedStatement(); + } + + return labelled; + } + + break; + } + case ir::AstNodeType::DO_WHILE_STATEMENT: + case ir::AstNodeType::WHILE_STATEMENT: + case ir::AstNodeType::FOR_UPDATE_STATEMENT: + case ir::AstNodeType::FOR_OF_STATEMENT: + case ir::AstNodeType::SWITCH_CASE_STATEMENT: + case ir::AstNodeType::SWITCH_STATEMENT: { + if (!target) { + return iter; + } + break; + } + default: { + break; + } + } + + iter = iter->Parent(); + } + + UNREACHABLE(); + return nullptr; +} + +binder::VariableFlags STSChecker::GetAccessFlagFromNode(const ir::AstNode *node) +{ + if (node->IsPrivate()) { + return binder::VariableFlags::PRIVATE; + } + + if (node->IsProtected()) { + return binder::VariableFlags::PROTECTED; + } + + return binder::VariableFlags::PUBLIC; +} +} // namespace panda::es2panda::checker diff --git a/checker/sts/narrowingConverter.cpp b/checker/sts/narrowingConverter.cpp new file mode 100644 index 000000000..cb70ab143 --- /dev/null +++ b/checker/sts/narrowingConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "narrowingConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/sts/narrowingConverter.h b/checker/sts/narrowingConverter.h new file mode 100644 index 000000000..2bfa6f13c --- /dev/null +++ b/checker/sts/narrowingConverter.h @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_NARROWING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_STS_NARROWING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { +class NarrowingConverter : public TypeConverter { +public: + explicit NarrowingConverter(STSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : TypeConverter(checker, relation, target, source) + { + if (!relation->ApplyNarrowing()) { + return; + } + + ASSERT(relation->GetNode()); + + switch (STSChecker::STSChecker::STSType(target)) { + case TypeFlag::BYTE: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_BYTE); + break; + } + case TypeFlag::CHAR: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_CHAR); + break; + } + case TypeFlag::SHORT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_FLOAT); + break; + } + + default: { + break; + } + } + } + +private: + template + void ApplyNarrowing(TypeFlag flag) + { + if (!source_->HasTypeFlag(flag)) { + return; + } + + switch (STSChecker::STSChecker::STSType(source_)) { + case TypeFlag::CHAR: { + ApplyNarrowing(); + break; + } + case TypeFlag::SHORT: { + ApplyNarrowing(); + break; + } + case TypeFlag::INT: { + ApplyNarrowing(); + break; + } + case TypeFlag::LONG: { + ApplyNarrowing(); + break; + } + case TypeFlag::FLOAT: { + ApplyNarrowing(); + break; + } + case TypeFlag::DOUBLE: { + ApplyNarrowing(); + break; + } + default: { + break; + } + } + } + + template + void ApplyNarrowing() + { + using SType = typename SourceType::UType; + using TType = typename TargetType::UType; + SType value = reinterpret_cast(source_)->GetValue(); + + if (util::Helpers::IsTargetFitInSourceRange(value)) { + relation_->GetNode()->SetTsType(checker_->Allocator()->New(static_cast(value))); + relation_->Result(true); + } else { + relation_->Result(RelationResult::ERROR); + } + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/sts/narrowingWideningConverter.cpp b/checker/sts/narrowingWideningConverter.cpp new file mode 100644 index 000000000..f79174d7f --- /dev/null +++ b/checker/sts/narrowingWideningConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/sts/narrowingWideningConverter.h b/checker/sts/narrowingWideningConverter.h new file mode 100644 index 000000000..388db4bc5 --- /dev/null +++ b/checker/sts/narrowingWideningConverter.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_NARROWING_WIDENING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_STS_NARROWING_WIDENING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/sts/narrowingConverter.h" +#include "plugins/ecmascript/es2panda/checker/sts/wideningConverter.h" + +namespace panda::es2panda::checker { +class NarrowingWideningConverter : public NarrowingConverter { +public: + explicit NarrowingWideningConverter(STSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : NarrowingConverter(checker, relation, target, source) + { + if (relation_->IsTrue() || relation_->IsError()) { + return; + } + + WideningConverter(checker, relation, target, source); + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/sts/object.cpp b/checker/sts/object.cpp new file mode 100644 index 000000000..e08e14180 --- /dev/null +++ b/checker/sts/object.cpp @@ -0,0 +1,794 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/expressionStatement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/functionExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/thisExpression.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsClassImplements.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" + +namespace panda::es2panda::checker { +STSObjectType *STSChecker::GetSuperType(STSObjectType *type) +{ + if (type->HasObjectFlag(STSObjectFlags::RESOLVED_SUPER)) { + return type->SuperType(); + } + + ASSERT(type->Variable() && type->GetDeclNode()->IsClassDefinition()); + auto *classDef = type->GetDeclNode()->AsClassDefinition(); + + if (!classDef->Super()) { + type->AddObjectFlag(STSObjectFlags::RESOLVED_SUPER); + if (type != globalBuiltinObjectType_) { + type->SetSuperType(globalBuiltinObjectType_); + } + return globalBuiltinObjectType_; + } + + TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, classDef->Ident()->Start()); + + Type *superType = classDef->Super()->AsTypeNode()->GetType(this); + + if (!superType->IsSTSObjectType() || !superType->AsSTSObjectType()->HasObjectFlag(STSObjectFlags::CLASS)) { + ThrowTypeError("Super type is not extensible.", classDef->Super()->Start()); + } + + STSObjectType *superObj = superType->AsSTSObjectType(); + + if (!(superObj->GetDeclNode()->IsOpen() || superObj->GetDeclNode()->IsAbstract())) { + ThrowTypeError("Cannot inherit without 'open'.", classDef->Super()->Start()); + } + + type->SetSuperType(superObj); + GetSuperType(superObj); + + type->AddObjectFlag(STSObjectFlags::RESOLVED_SUPER); + return type->SuperType(); +} + +void STSChecker::ValidateImplementedInterface(STSObjectType *type, Type *interface, + std::unordered_set *extendsSet, const lexer::SourcePosition &pos) +{ + if (!interface->IsSTSObjectType() || !interface->AsSTSObjectType()->HasObjectFlag(STSObjectFlags::INTERFACE)) { + ThrowTypeError("Interface expected here.", pos); + } + + if (!extendsSet->insert(interface).second) { + ThrowTypeError("Repeated interface.", pos); + } + + type->AddInterface(interface->AsSTSObjectType()); + GetInterfacesOfInterface(interface->AsSTSObjectType()); +} + +ArenaVector STSChecker::GetInterfacesOfClass(STSObjectType *type) +{ + const auto *declNode = type->GetDeclNode()->AsClassDefinition(); + + std::unordered_set extendsSet; + for (auto *it : declNode->Implements()) { + ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start()); + } + + return type->Interfaces(); +} + +ArenaVector STSChecker::GetInterfacesOfInterface(STSObjectType *type) +{ + const auto *declNode = type->GetDeclNode()->AsTSInterfaceDeclaration(); + + TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, declNode->Id()->Start()); + + std::unordered_set extendsSet; + for (auto *it : declNode->Extends()) { + ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start()); + } + + return type->Interfaces(); +} + +ArenaVector STSChecker::GetInterfaces(STSObjectType *type) +{ + if (type->HasObjectFlag(STSObjectFlags::RESOLVED_INTERFACES)) { + return type->Interfaces(); + } + + ASSERT(type->GetDeclNode()->IsClassDefinition() || type->GetDeclNode()->IsTSInterfaceDeclaration()); + + if (type->GetDeclNode()->IsClassDefinition()) { + GetInterfacesOfClass(type); + } else { + GetInterfacesOfInterface(type); + } + + type->AddObjectFlag(STSObjectFlags::RESOLVED_INTERFACES); + return type->Interfaces(); +} + +void STSChecker::SetTypeParameterType(ir::TSTypeParameter *typeParam, Type *assemblerType) +{ + auto *var = typeParam->Name()->Variable(); + auto *typeParamType = CreateTypeParameter(assemblerType); + typeParamType->SetVariable(var); + var->SetTsType(typeParamType); +} + +void STSChecker::CreateTypeForTypeParameters(STSObjectType *type, ir::TSTypeParameterDeclaration *typeParams) +{ + if (type->HasObjectFlag(STSObjectFlags::RESOLVED_TYPE_PARAMS)) { + return; + } + + checker::ScopeContext scopeCtx(this, typeParams->Scope()); + + for (auto *param : typeParams->Params()) { + Type *paramType = globalBuiltinObjectType_; + + if (param->Constraint()) { + auto *constraintType = param->Constraint()->GetType(this); + + if (!constraintType->IsSTSObjectType()) { + ThrowTypeError("Extends constraint must be an object", param->Constraint()->Start()); + } + + paramType = constraintType; + } + + SetTypeParameterType(param, paramType); + } + + type->AddObjectFlag(STSObjectFlags::RESOLVED_TYPE_PARAMS); +} + +void STSChecker::CreateTypeForInterfaceTypeParameters(STSObjectType *type) +{ + ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + CreateTypeForTypeParameters(type, typeParams); +} + +void STSChecker::CreateTypeForClassTypeParameters(STSObjectType *type) +{ + ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + CreateTypeForTypeParameters(type, typeParams); +} + +STSObjectType *STSChecker::BuildInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl) +{ + auto *refVar = interfaceDecl->Id()->Variable(); + ASSERT(refVar); + refVar->AddFlag(binder::VariableFlags::INTERFACE); + + checker::STSObjectType *interfaceType {}; + if (!refVar->TsType()) { + interfaceType = CreateSTSObjectType(refVar->Name(), interfaceDecl, checker::STSObjectFlags::INTERFACE); + interfaceType->SetVariable(refVar); + refVar->SetTsType(interfaceType); + } else { + interfaceType = refVar->TsType()->AsSTSObjectType(); + } + + if (interfaceDecl->TypeParams()) { + CreateTypeForInterfaceTypeParameters(interfaceType); + } + + GetInterfacesOfInterface(interfaceType); + + checker::ScopeContext scopeCtx(this, interfaceDecl->Scope()); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_INTERFACE, interfaceType); + + ResolveDeclaredMembersOfObject(interfaceType); + + return interfaceType; +} + +STSObjectType *STSChecker::BuildClassProperties(ir::ClassDefinition *classDef) +{ + if (classDef->IsOpen() && classDef->IsAbstract()) { + ThrowTypeError("Cannot use both 'open' and 'abstract' modifiers.", classDef->Start()); + } + + const util::StringView &className = classDef->Ident()->Name(); + auto *classScope = classDef->Scope(); + binder::ScopeFindResult result = classScope->Find(className); + ASSERT(result.variable); + result.variable->AddFlag(binder::VariableFlags::CLASS); + + checker::STSObjectType *classType {}; + if (!result.variable->TsType()) { + classType = CreateSTSObjectType(className, classDef, checker::STSObjectFlags::CLASS); + classType->SetVariable(result.variable); + result.variable->SetTsType(classType); + if (classDef->IsAbstract()) { + classType->AddObjectFlag(checker::STSObjectFlags::ABSTRACT); + } + } else { + classType = result.variable->TsType()->AsSTSObjectType(); + } + + classDef->SetTsType(classType); + + if (classDef->TypeParams()) { + CreateTypeForClassTypeParameters(classType); + } + + if (!classType->HasObjectFlag(STSObjectFlags::RESOLVED_SUPER)) { + GetSuperType(classType); + GetInterfacesOfClass(classType); + } + + if (classType->HasObjectFlag(STSObjectFlags::RESOLVED_MEMBERS)) { + return classType; + } + + checker::ScopeContext scopeCtx(this, classScope); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_CLASS, classType); + + ResolveDeclaredMembersOfObject(classType); + + return classType; +} + +STSObjectType *STSChecker::BuildAnonymousClassProperties(ir::ClassDefinition *classDef, STSObjectType *superType) +{ + auto classType = CreateSTSObjectType(classDef->Ident()->Name(), classDef, checker::STSObjectFlags::CLASS); + classDef->SetTsType(classType); + classType->SetSuperType(superType); + classType->AddObjectFlag(checker::STSObjectFlags::RESOLVED_SUPER); + + checker::ScopeContext scopeCtx(this, classDef->Scope()); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_CLASS, classType); + + ResolveDeclaredMembersOfObject(classType); + + return classType; +} + +void STSChecker::ResolveDeclaredMembersOfObject(STSObjectType *type) +{ + if (type->HasObjectFlag(STSObjectFlags::RESOLVED_MEMBERS)) { + return; + } + + auto *declNode = type->GetDeclNode(); + auto &body = declNode->IsTSInterfaceDeclaration() ? declNode->AsTSInterfaceDeclaration()->Body()->Body() + : declNode->AsClassDefinition()->Body(); + + for (auto *it : body) { + bool addStatic = it->IsStatic(); + util::StringView memberName {}; + + switch (it->Type()) { + case ir::AstNodeType::CLASS_PROPERTY: { + auto *element = it->AsClassElement(); + memberName = element->Id()->Name(); + break; + } + case ir::AstNodeType::METHOD_DEFINITION: { + auto *methodDef = it->AsMethodDefinition(); + auto *funcType = BuildMethodSignature(methodDef); + methodDef->SetTsType(funcType); + memberName = methodDef->Id()->Name(); + + if (methodDef->IsConstructor()) { + addStatic = true; + type->AddConstructSignature(funcType->CallSignatures()); + } + + break; + } + case ir::AstNodeType::CLASS_DECLARATION: { + auto *classDecl = it->AsClassDeclaration(); + memberName = classDecl->Definition()->Ident()->Name(); + break; + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + auto *interfaceDecl = it->AsTSInterfaceDeclaration(); + memberName = interfaceDecl->Id()->Name(); + break; + } + case ir::AstNodeType::CLASS_STATIC_BLOCK: { + memberName = compiler::Signatures::CCTOR; + break; + } + default: { + continue; + } + } + + binder::ScopeFindResult res = scope_->Find(memberName); + ASSERT(res.variable); + + if (addStatic) { + res.variable->AddFlag(binder::VariableFlags::STATIC); + } + + if (!it->IsMethodDefinition()) { + res.variable->AddFlag(GetAccessFlagFromNode(it)); + } + + type->AddProperty(res.variable->AsLocalVariable()); + } + + type->AddObjectFlag(STSObjectFlags::RESOLVED_MEMBERS); + return; +} + +const std::vector STSChecker::CollectAbstractSignaturesFromObject(STSObjectType *objType) +{ + std::vector abstracts; + for (const auto &[_, prop] : objType->Properties()) { + if (!prop->TsType() || !prop->TsType()->IsSTSFunctionType()) { + continue; + } + + auto *funcType = prop->TsType()->AsSTSFunctionType(); + for (auto *sig : funcType->CallSignatures()) { + if (sig->HasSignatureFlag(SignatureFlags::ABSTRACT) && !sig->HasSignatureFlag(SignatureFlags::PRIVATE)) { + abstracts.push_back(sig); + } + } + } + + return abstracts; +} + +void STSChecker::CreateFunctionTypesFromAbstracts(const std::vector &abstracts, + ArenaVector *target) +{ + for (auto *it : abstracts) { + auto name = it->Function()->Id()->Name(); + auto *found = FindFunctionInVectorGivenByName(name, *target); + if (found) { + found->AddCallSignature(it); + continue; + } + + auto *created = CreateSTSFunctionType(it); + created->AddTypeFlag(TypeFlag::SYNTHETIC); + target->push_back(created); + } +} + +void STSChecker::ComputeAbstractsFromInterface(STSObjectType *interfaceType) +{ + auto cached = cachedComputedAbstracts_.find(interfaceType); + if (cached != cachedComputedAbstracts_.end()) { + return; + } + + for (auto *it : interfaceType->Interfaces()) { + ComputeAbstractsFromInterface(it); + } + + ArenaVector merged(allocator_.Adapter()); + CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(interfaceType), &merged); + std::unordered_set abstractInheritanceTarget; + + for (auto *interface : interfaceType->Interfaces()) { + auto found = cachedComputedAbstracts_.find(interface); + ASSERT(found != cachedComputedAbstracts_.end()); + + if (!abstractInheritanceTarget.insert(found->first).second) { + continue; + } + + MergeComputedAbstracts(merged, found->second.first); + + for (auto *base : found->second.second) { + abstractInheritanceTarget.insert(base); + } + } + + cachedComputedAbstracts_.insert({interfaceType, {merged, abstractInheritanceTarget}}); +} + +ArenaVector &STSChecker::GetAbstractsForClass(STSObjectType *classType) +{ + ArenaVector merged(allocator_.Adapter()); + CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(classType), &merged); + + std::unordered_set abstractInheritanceTarget; + if (classType->SuperType()) { + auto base = cachedComputedAbstracts_.find(classType->SuperType()); + ASSERT(base != cachedComputedAbstracts_.end()); + MergeComputedAbstracts(merged, base->second.first); + + abstractInheritanceTarget.insert(base->first); + for (auto *it : base->second.second) { + abstractInheritanceTarget.insert(it); + } + } + + for (auto *it : classType->Interfaces()) { + ComputeAbstractsFromInterface(it); + auto found = cachedComputedAbstracts_.find(it); + ASSERT(found != cachedComputedAbstracts_.end()); + + if (!abstractInheritanceTarget.insert(found->first).second) { + continue; + } + + MergeComputedAbstracts(merged, found->second.first); + + for (auto *interface : found->second.second) { + abstractInheritanceTarget.insert(interface); + } + } + + return cachedComputedAbstracts_.insert({classType, {merged, abstractInheritanceTarget}}).first->second.first; +} + +void STSChecker::ValidateOverriding(STSObjectType *classType, const lexer::SourcePosition &pos) +{ + if (classType->HasObjectFlag(STSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS)) { + return; + } + + bool throwError = true; + if (classType->HasObjectFlag(STSObjectFlags::ABSTRACT)) { + throwError = false; + } + + if (classType->SuperType()) { + ValidateOverriding(classType->SuperType(), classType->SuperType()->GetDeclNode()->Start()); + } + + auto &abstractsToBeImplemented = GetAbstractsForClass(classType); + std::vector implementedSignatures; + + auto *superIter = classType; + do { + for (auto it = abstractsToBeImplemented.begin(); it != abstractsToBeImplemented.end(); it++) { + for (const auto &[_, prop] : superIter->Properties()) { + if (!prop || !prop->TsType() || !prop->TsType()->IsSTSFunctionType()) { + continue; + } + AddImplementedSignature(&implementedSignatures, prop, *it); + } + } + superIter = superIter->SuperType(); + } while (superIter); + + SavedTypeRelationFlagsContext savedFlagsCtx(relation_, TypeRelationFlag::NO_RETURN_TYPE_CHECK); + bool functionOverridden; + bool foundSignature; + for (auto it = abstractsToBeImplemented.begin(); it != abstractsToBeImplemented.end();) { + functionOverridden = false; + for (auto abstractSignature = (*it)->CallSignatures().begin(); + abstractSignature != (*it)->CallSignatures().end();) { + foundSignature = false; + for (auto implemented : implementedSignatures) { + if (relation_->IsIdenticalTo(*abstractSignature, implemented) && + (*abstractSignature)->Function()->Id()->Name() == implemented->Function()->Id()->Name() && + IsTypeAssignableTo(implemented->ReturnType(), (*abstractSignature)->ReturnType())) { + if (!implemented->Function()->IsOverride() && (implemented->Owner() == classType)) { + ThrowTypeError("Method overriding is only allowed with 'override' modifier", + implemented->Function()->Start()); + } + if ((*it)->CallSignatures().size() > 1) { + abstractSignature = (*it)->CallSignatures().erase(abstractSignature); + foundSignature = true; + } else { + it = abstractsToBeImplemented.erase(it); + functionOverridden = true; + } + implemented->AddSignatureFlag(SignatureFlags::OPEN); + + break; + } + } + if (functionOverridden) { + break; + } + if (!foundSignature) { + abstractSignature++; + } + } + if (!functionOverridden) { + it++; + } + } + + if (abstractsToBeImplemented.size() > 0 && throwError) { + auto unimplementedSignature = abstractsToBeImplemented.front()->CallSignatures().front(); + ThrowTypeError({classType->Name(), " is not abstract and does not override abstract method ", + unimplementedSignature->Function()->Id()->Name(), unimplementedSignature, " in ", + GetContainingObjectNameFromSignature(unimplementedSignature)}, + pos); + } + + classType->AddObjectFlag(STSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS); +} + +void STSChecker::AddImplementedSignature(std::vector *implementedSignatures, + binder::LocalVariable *function, STSFunctionType *it) +{ + for (auto signature : function->TsType()->AsSTSFunctionType()->CallSignatures()) { + if (signature->Function()->IsAbstract() || signature->Function()->IsStatic()) { + continue; + } + if (signature->Function()->Id()->Name() == it->Name()) { + implementedSignatures->emplace_back(signature); + } + } +} + +void STSChecker::CheckClassDefinition(ir::ClassDefinition *classDef) +{ + auto *classType = classDef->TsType()->AsSTSObjectType(); + auto *enclosingClass = context_.ContainingClass(); + auto newStatus = checker::CheckerStatus::IN_CLASS; + classType->SetEnclosingType(enclosingClass); + + if (!classDef->IsStatic() && enclosingClass && !enclosingClass->HasObjectFlag(STSObjectFlags::GLOBAL)) { + newStatus |= CheckerStatus::INNER_CLASS; + } + + if (classDef->IsGlobal()) { + classType->AddObjectFlag(checker::STSObjectFlags::GLOBAL); + } + + checker::ScopeContext scopeCtx(this, classDef->Scope()); + auto savedContext = SavedCheckerContext(this, newStatus, classType); + + if (classDef->IsAbstract()) { + AddStatus(checker::CheckerStatus::IN_ABSTRACT); + classType->AddObjectFlag(checker::STSObjectFlags::ABSTRACT); + } + + if (classDef->IsStatic() && !context_.ContainingClass()->HasObjectFlag(STSObjectFlags::GLOBAL)) { + AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT); + } + + for (auto *it : classDef->Body()) { + if (it->IsClassProperty()) { + it->Check(this); + } + } + + for (auto *it : classDef->Body()) { + if (!it->IsClassProperty()) { + it->Check(this); + } + } + + if (classDef->IsGlobal()) { + return; + } + + for (auto *it : classType->ConstructSignatures()) { + CheckCyclicContructorCall(it); + } + + ValidateOverriding(classType, classDef->Start()); + CheckConstFields(classType); +} + +void STSChecker::CheckConstFields(const STSObjectType *classType) +{ + for (const auto &[_, prop] : classType->Properties()) { + if (!prop->Declaration()->IsConstDecl() || !prop->HasFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED)) { + continue; + } + CheckConstFieldInitialized(classType, prop); + } +} + +void STSChecker::CheckConstFieldInitialized(const STSObjectType *classType, binder::LocalVariable *classVar) +{ + const bool classVarStatic = classVar->Declaration()->Node()->AsClassProperty()->IsStatic(); + for (const auto &[_, prop] : classType->Properties()) { + if (!prop->TsType()->IsSTSFunctionType()) { + continue; + } + + const auto &callSigs = prop->TsType()->AsSTSFunctionType()->CallSignatures(); + for (const auto *signature : callSigs) { + if ((signature->Function()->IsConstructor() && !classVarStatic) || + (signature->Function()->IsStaticBlock() && classVarStatic)) { + CheckConstFieldInitialized(signature, classVar); + } + } + } +} + +void STSChecker::FindAssignment(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized) +{ + if (node->IsAssignmentExpression() && node->AsAssignmentExpression()->Target() == classVar) { + if (initialized) { + ThrowTypeError({"Variable '", classVar->Declaration()->Name(), "' might already have been initialized"}, + node->Start()); + } + initialized = true; + return; + } + FindAssignments(node, classVar, initialized); +} + +void STSChecker::FindAssignments(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized) +{ + node->Iterate( + [this, classVar, &initialized](ir::AstNode *childNode) { FindAssignment(childNode, classVar, initialized); }); +} + +void STSChecker::CheckConstFieldInitialized(const Signature *signature, binder::LocalVariable *classVar) +{ + bool initialized = false; + const auto &stmts = signature->Function()->Body()->AsBlockStatement()->Statements(); + const auto it = stmts.begin(); + + if (it != stmts.end()) { + if (const auto *first = *it; + first->IsExpressionStatement() && first->AsExpressionStatement()->GetExpression()->IsCallExpression() && + first->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression()) { + initialized = true; + } + } + + // TODO(szd) control flow + FindAssignments(signature->Function()->Body(), classVar, initialized); + if (!initialized) { + ThrowTypeError({"Variable '", classVar->Declaration()->Name(), "' might not have been initialized"}, + signature->Function()->End()); + } + + classVar->RemoveFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED); +} + +void STSChecker::CheckInnerClassMembers(const STSObjectType *classType) +{ + const auto &innerProps = classType->Properties(); + for (const auto &[_, innerProp] : innerProps) { + if (innerProp->TsType()->IsSTSFunctionType()) { + const auto &callSigs = innerProp->TsType()->AsSTSFunctionType()->CallSignatures(); + for (auto *sig : callSigs) { + if (sig->Function()->IsStatic()) { + ThrowTypeError("Inner class cannot have static methods", sig->Function()->Id()->Start()); + } + } + } else if (innerProp->Declaration()->IsLetOrConstDecl() && + innerProp->Declaration()->Node()->IsClassProperty()) { + const auto *classProp = innerProp->Declaration()->Node()->AsClassProperty(); + if (classProp->IsStatic() && !(classProp->IsConst())) { + ThrowTypeError("Inner class cannot have non-const static properties", classProp->Start()); + } + } + } +} + +Type *STSChecker::ValidateArrayIndex(ir::Expression *expr) +{ + Type *indexType = ApplyUnaryOperatorPromotion(expr->Check(this)); + + if (!indexType->HasTypeFlag(TypeFlag::STS_ARRAY_INDEX)) { + ThrowTypeError("Only intergal types can be used as index.", expr->Start()); + } + + return indexType; +} + +Type *STSChecker::CheckArrayElementAccess(ir::MemberExpression *expr) +{ + Type *arrayType = expr->Object()->Check(this); + + if (!arrayType->IsSTSArrayType()) { + ThrowTypeError("Indexed access expression can only be used in array type.", expr->Object()->Start()); + } + + ValidateArrayIndex(expr->Property()); + + // TODO: apply capture conversion on this type + return arrayType->AsSTSArrayType()->ElementType(); +} + +STSObjectType *STSChecker::CheckThisOrSuperAccess(ir::Expression *node, STSObjectType *classType, std::string_view msg) +{ + if (classType->GetDeclNode()->AsClassDefinition()->IsGlobal() || + (!node->Parent()->IsMemberExpression() && !node->Parent()->IsCallExpression())) { + ThrowTypeError({"Cannot reference", msg, "in this context."}, node->Start()); + } + + return classType; +} + +void STSChecker::CheckCyclicContructorCall(Signature *signature) +{ + ASSERT(signature->Function()); + + if (!signature->Function()->Body()) { + return; + } + + auto *funcBody = signature->Function()->Body()->AsBlockStatement(); + + TypeStackElement tse(this, signature, "Recursive constructor invocation", signature->Function()->Start()); + + if (!funcBody->Statements().empty() && funcBody->Statements()[0]->IsExpressionStatement() && + funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->IsCallExpression() && + funcBody->Statements()[0] + ->AsExpressionStatement() + ->GetExpression() + ->AsCallExpression() + ->Callee() + ->IsThisExpression()) { + auto *constructorCall = funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->AsCallExpression(); + ASSERT(constructorCall->Signature()); + CheckCyclicContructorCall(constructorCall->Signature()); + } +} + +STSObjectType *STSChecker::CheckExceptionType(checker::Type *type, lexer::SourcePosition pos) +{ + auto *exceptionType = + CheckException(type, pos, globalBuiltinExceptionType_, compiler::Signatures::BUILTIN_EXCEPTION_CLASS); + + if (relation_->IsAssignableTo(exceptionType, globalBuiltinRuntimeExceptionType_)) { + ThrowTypeError({"Recover clause must be used for any instance of '", exceptionType->Name(), "'"}, pos); + } + + return exceptionType; +} + +STSObjectType *STSChecker::CheckRuntimeExceptionType(checker::Type *type, lexer::SourcePosition pos) +{ + return CheckException(type, pos, globalBuiltinRuntimeExceptionType_, + compiler::Signatures::BUILTIN_RUNTIME_EXCEPTION_CLASS); +} + +STSObjectType *STSChecker::CheckException(checker::Type *type, lexer::SourcePosition pos, STSObjectType *expected, + std::string_view msg) +{ + if (!type->IsSTSObjectType() || !relation_->IsAssignableTo(type, expected)) { + ThrowTypeError({"Argument must be an instance of '", msg, "'"}, pos); + } + + return type->AsSTSObjectType(); +} + +Type *STSChecker::TryToInstantiate(Type *type, ArenaAllocator *allocator, TypeRelation *relation, + GlobalTypesHolder *globalTypes) +{ + if (type->IsSTSTypeReference() || type->IsSTSFunctionType() || + (type->IsSTSObjectType() && type->AsSTSObjectType()->HasObjectFlag(STSObjectFlags::UNCOMPLETE_INSTANTIATION))) { + return type->Instantiate(allocator, relation, globalTypes); + } + + return type; +} + +} // namespace panda::es2panda::checker diff --git a/checker/sts/primitiveWrappers.cpp b/checker/sts/primitiveWrappers.cpp new file mode 100644 index 000000000..fba7f28cc --- /dev/null +++ b/checker/sts/primitiveWrappers.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "primitiveWrappers.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/sts/primitiveWrappers.h b/checker/sts/primitiveWrappers.h new file mode 100644 index 000000000..47dd0af1a --- /dev/null +++ b/checker/sts/primitiveWrappers.h @@ -0,0 +1,58 @@ + +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_PRIMITIVEWRAPPERS_H +#define ES2PANDA_COMPILER_CHECKER_STS_PRIMITIVEWRAPPERS_H + +#include "plugins/ecmascript/es2panda/checker/types/sts/stsObjectType.h" + +namespace panda::es2panda::checker { +class STSObjectType; + +using WrapperDesc = ArenaUnorderedMap>; + +class PrimitiveWrappers { +public: + explicit PrimitiveWrappers(ArenaAllocator *allocator) : wrappers_(allocator->Adapter()) + { + wrappers_.insert({"Boolean", {nullptr, STSObjectFlags::BUILTIN_BOOLEAN}}); + wrappers_.insert({"Byte", {nullptr, STSObjectFlags::BUILTIN_BYTE}}); + wrappers_.insert({"Char", {nullptr, STSObjectFlags::BUILTIN_CHAR}}); + wrappers_.insert({"Short", {nullptr, STSObjectFlags::BUILTIN_SHORT}}); + wrappers_.insert({"Int", {nullptr, STSObjectFlags::BUILTIN_INT}}); + wrappers_.insert({"Long", {nullptr, STSObjectFlags::BUILTIN_LONG}}); + wrappers_.insert({"Float", {nullptr, STSObjectFlags::BUILTIN_FLOAT}}); + wrappers_.insert({"Double", {nullptr, STSObjectFlags::BUILTIN_DOUBLE}}); + } + NO_COPY_SEMANTIC(PrimitiveWrappers); + NO_MOVE_SEMANTIC(PrimitiveWrappers); + ~PrimitiveWrappers() = default; + + WrapperDesc &Wrappers() + { + return wrappers_; + } + + const WrapperDesc &Wrappers() const + { + return wrappers_; + } + +private: + WrapperDesc wrappers_; +}; +} // namespace panda::es2panda::checker +#endif diff --git a/checker/sts/typeConverter.cpp b/checker/sts/typeConverter.cpp new file mode 100644 index 000000000..90beaa535 --- /dev/null +++ b/checker/sts/typeConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "typeConverter.h" + +namespace panda::es2panda::checker { +} diff --git a/checker/sts/typeConverter.h b/checker/sts/typeConverter.h new file mode 100644 index 000000000..00822b115 --- /dev/null +++ b/checker/sts/typeConverter.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_TYPE_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_STS_TYPE_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class STSChecker; + +class TypeConverter { +public: + TypeConverter(STSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : checker_(checker), relation_(relation), target_(target), source_(source) + { + } + + Type *Result() + { + return result_; + } + +protected: + STSChecker *checker_; + TypeRelation *relation_; + Type *target_; + Type *source_; + Type *result_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/sts/typeCreation.cpp b/checker/sts/typeCreation.cpp new file mode 100644 index 000000000..d7b3272a4 --- /dev/null +++ b/checker/sts/typeCreation.cpp @@ -0,0 +1,277 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsScript.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { +ByteType *STSChecker::CreateByteType(int8_t value) +{ + return allocator_.New(value); +} + +STSBooleanType *STSChecker::CreateSTSBooleanType(bool value) +{ + return allocator_.New(value); +} + +DoubleType *STSChecker::CreateDoubleType(double value) +{ + return allocator_.New(value); +} + +FloatType *STSChecker::CreateFloatType(float value) +{ + return allocator_.New(value); +} + +IntType *STSChecker::CreateIntType(int32_t value) +{ + return allocator_.New(value); +} + +IntType *STSChecker::CreateIntTypeFromType(Type *type) +{ + if (!type->HasTypeFlag(TypeFlag::CONSTANT)) { + return GlobalIntType()->AsIntType(); + } + + if (type->IsIntType()) { + return type->AsIntType(); + } + + switch (STSType(type)) { + case TypeFlag::CHAR: { + return CreateIntType(static_cast(type->AsCharType()->GetValue())); + } + case TypeFlag::BYTE: { + return CreateIntType(static_cast(type->AsByteType()->GetValue())); + } + case TypeFlag::SHORT: { + return CreateIntType(static_cast(type->AsShortType()->GetValue())); + } + default: { + return nullptr; + } + } +} + +LongType *STSChecker::CreateLongType(int64_t value) +{ + return allocator_.New(value); +} + +ShortType *STSChecker::CreateShortType(int16_t value) +{ + return allocator_.New(value); +} + +CharType *STSChecker::CreateCharType(char16_t value) +{ + return allocator_.New(value); +} + +STSStringType *STSChecker::CreateSTSStringType(util::StringView value) +{ + return allocator_.New(&allocator_, globalBuiltinStringType_, value); +} + +STSArrayType *STSChecker::CreateSTSArrayType(Type *elementType) +{ + auto res = arrayTypes_.find(elementType); + + if (res != arrayTypes_.end()) { + return res->second; + } + + auto *arrayType = allocator_.New(elementType); + arrayTypes_.insert({elementType, arrayType}); + + return arrayType; +} + +STSFunctionType *STSChecker::CreateSTSFunctionType(Signature *signature) +{ + return allocator_.New(signature->Function()->Id()->Name(), signature, &allocator_); +} + +Signature *STSChecker::CreateSignature(SignatureInfo *info, Type *returnType, ir::ScriptFunction *func) +{ + return allocator_.New(info, returnType, func); +} + +Signature *STSChecker::CreateSignature(SignatureInfo *info, Type *returnType, util::StringView internalName) +{ + return allocator_.New(info, returnType, internalName); +} + +SignatureInfo *STSChecker::CreateSignatureInfo() +{ + return allocator_.New(&allocator_); +} + +STSTypeParameter *STSChecker::CreateTypeParameter(Type *assemblerType) +{ + return allocator_.New(assemblerType); +} + +STSTypeReference *STSChecker::CreateTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *refVar) +{ + return allocator_.New(ref, assemblerRef, refVar); +} + +STSFunctionType *STSChecker::CreateSTSFunctionType(util::StringView name) +{ + return allocator_.New(name, &allocator_); +} + +STSObjectType *STSChecker::CreateSTSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, + STSObjectFlags flags) +{ + if (name == compiler::Signatures::BUILTIN_STRING_CLASS) { + if (globalBuiltinStringType_) { + return globalBuiltinStringType_; + } + globalBuiltinStringType_ = + CreateNewSTSObjectType(name, declNode, flags | STSObjectFlags::BUILTIN_STRING | STSObjectFlags::STRING); + + globalTypes_->GlobalTypes()[static_cast(GlobalTypeId::STS_STRING)] = + allocator_.New(&allocator_, globalBuiltinStringType_); + return globalBuiltinStringType_; + } + + auto *objType = CreateNewSTSObjectType(name, declNode, flags); + + if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) { + if (globalBuiltinObjectType_) { + return globalBuiltinObjectType_; + } + globalBuiltinObjectType_ = objType; + } else if (name == compiler::Signatures::BUILTIN_EXCEPTION_CLASS) { + if (globalBuiltinExceptionType_) { + return globalBuiltinExceptionType_; + } + globalBuiltinExceptionType_ = objType; + } else if (name == compiler::Signatures::BUILTIN_RUNTIME_EXCEPTION_CLASS) { + if (globalBuiltinRuntimeExceptionType_) { + return globalBuiltinRuntimeExceptionType_; + } + globalBuiltinRuntimeExceptionType_ = objType; + } else if (name == compiler::Signatures::BUILTIN_CLASS_CLASS) { + if (globalBuiltinClassType_) { + return globalBuiltinClassType_; + } + globalBuiltinClassType_ = objType; + } + + return objType; +} + +STSObjectType *STSChecker::CreateSTSObjectType(util::StringView name, ir::AstNode *declNode, STSObjectFlags flags) +{ + auto res = primitiveWrappers_.Wrappers().find(name); + if (res == primitiveWrappers_.Wrappers().end()) { + return CreateSTSObjectTypeCheckBuiltins(name, declNode, flags); + } + + if (res->second.first) { + return res->second.first; + } + + auto *objType = CreateNewSTSObjectType(name, declNode, flags | res->second.second); + primitiveWrappers_.Wrappers().at(name).first = objType; + return objType; +} + +STSObjectType *STSChecker::CreateNewSTSObjectType(util::StringView name, ir::AstNode *declNode, STSObjectFlags flags) +{ + util::StringView assemblerName = name; + util::StringView prefix {}; + + auto *containingClass = util::Helpers::GetContainingClassDefinition(declNode->Parent()); + + if (containingClass) { + prefix = containingClass->TsType()->AsSTSObjectType()->AssemblerName(); + } else { + auto *containingInterface = util::Helpers::GetContainingClassDefinition(declNode->Parent()); + + if (containingInterface) { + prefix = containingInterface->TsType()->AsSTSObjectType()->AssemblerName(); + } else { + auto *program = static_cast(declNode->GetTopStatement())->Program(); + prefix = program->GetPackageName(); + } + } + + if (!prefix.Empty()) { + util::UString fullPath(prefix, &allocator_); + fullPath.Append('.'); + fullPath.Append(name); + assemblerName = fullPath.View(); + } + + return allocator_.New(&allocator_, name, assemblerName, declNode, flags); +} + +std::tuple STSChecker::CreateBuiltinArraySignatureInfo(STSArrayType *arrayType, + size_t dim) +{ + std::stringstream ss; + arrayType->ToAssemblerType(ss); + ss << compiler::Signatures::METHOD_SEPARATOR << compiler::Signatures::CTOR << compiler::Signatures::MANGLE_BEGIN; + arrayType->ToAssemblerType(ss); + + auto *info = CreateSignatureInfo(); + info->minArgCount = dim; + + for (size_t i = 0; i < dim; i++) { + util::UString param(std::to_string(i), Allocator()); + auto *paramVar = binder::Scope::CreateVar(Allocator(), param.View(), binder::VariableFlags::NONE, nullptr); + paramVar->SetTsType(GlobalIntType()); + + info->params.push_back(paramVar); + + ss << compiler::Signatures::MANGLE_SEPARATOR << compiler::Signatures::PRIMITIVE_INT; + } + + ss << compiler::Signatures::MANGLE_SEPARATOR << compiler::Signatures::PRIMITIVE_VOID + << compiler::Signatures::MANGLE_SEPARATOR; + auto internalName = util::UString(ss.str(), Allocator()).View(); + + return {internalName, info}; +} + +Signature *STSChecker::CreateBuiltinArraySignature(STSArrayType *arrayType, size_t dim) +{ + auto res = globalArraySignatures_.find(arrayType); + + if (res != globalArraySignatures_.end()) { + return res->second; + } + + auto [internalName, info] = CreateBuiltinArraySignatureInfo(arrayType, dim); + auto *signature = CreateSignature(info, GlobalVoidType(), internalName); + globalArraySignatures_.insert({arrayType, signature}); + + return signature; +} +} // namespace panda::es2panda::checker diff --git a/checker/sts/typeRelationContext.cpp b/checker/sts/typeRelationContext.cpp new file mode 100644 index 000000000..b09fa3531 --- /dev/null +++ b/checker/sts/typeRelationContext.cpp @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "typeRelationContext.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/ir/expressions/arrayExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsArrayType.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" + +namespace panda::es2panda::checker { +void AssignmentContext::ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node, + STSArrayType *target) +{ + for (uint32_t index = 0; index < node->Elements().size(); index++) { + ir::Expression *currentArrayElem = node->Elements()[index]; + AssignmentContext(relation, currentArrayElem, currentArrayElem->Check(relation->GetChecker()->AsSTSChecker()), + target->ElementType(), currentArrayElem->Start(), + {"Array element at index ", index, " is not compatible with the target array element type."}); + } +} + +bool InstantiationContext::ValidateTypeArguments(STSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs, + const lexer::SourcePosition &pos) +{ + if (typeParamDecl && !typeArgs) { + checker_->ThrowTypeError({"Type '", type, "' is generic but type argument were not provided."}, pos); + } + + if (!typeArgs) { + result_ = type; + return true; + } + + if (typeParamDecl->Params().size() != typeArgs->Params().size()) { + checker_->ThrowTypeError({"Type '", type, "' has ", typeParamDecl->Params().size(), + " number of type parameters, but ", typeArgs->Params().size(), + " type arguments were provided."}, + pos); + } + + return false; +} + +util::StringView InstantiationContext::GetHashFromTypeArguments(ArenaVector &typeArgTypes) +{ + std::stringstream ss; + + for (auto *it : typeArgTypes) { + // TODO: this is not the best solution, since A and A will produce the same string in their ToString + // method, but they are two different types + it->ToString(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + return util::UString(ss.str(), checker_->Allocator()).View(); +} + +void InstantiationContext::InstantiateType(STSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs) +{ + ArenaVector typeArgTypes(checker_->Allocator()->Adapter()); + typeArgTypes.reserve(typeArgs->Params().size()); + + auto flags = STSObjectFlags::NO_OPTS; + + for (auto *it : typeArgs->Params()) { + auto *paramType = it->GetType(checker_); + typeArgTypes.push_back(it->GetType(checker_)); + + if (paramType->IsSTSTypeReference()) { + flags |= STSObjectFlags::UNCOMPLETE_INSTANTIATION; + } + } + + InstantiateType(type, typeParamDecl, typeArgTypes); + result_->AddObjectFlag(flags); +} + +void InstantiationContext::InstantiateType(STSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ArenaVector &typeArgTypes) +{ + util::StringView hash = GetHashFromTypeArguments(typeArgTypes); + auto *found = type->GetInstantiatedType(hash); + + if (found) { + result_ = found; + return; + } + + checker::ScopeContext scopeCtx(checker_, typeParamDecl->Scope()); + + for (size_t idx = 0; idx < typeParamDecl->Params().size(); idx++) { + auto *paramVar = typeParamDecl->Params()[idx]->Name()->Variable()->AsLocalVariable(); + auto *typeParam = paramVar->TsType()->AsSTSTypeParameter(); + + typeParam->SetType(typeArgTypes[idx]); + typeArgVars_.push_back(paramVar); + } + + result_ = type->Instantiate(checker_->Allocator(), checker_->Relation(), checker_->GetGlobalTypesHolder()) + ->AsSTSObjectType(); + result_->SetTypeArguments(std::move(typeArgTypes)); + type->GetInstantiationMap().insert({hash, result_}); + + for (auto *it : typeArgVars_) { + it->TsType()->AsSTSTypeParameter()->SetType(nullptr); + } +} +} // namespace panda::es2panda::checker diff --git a/checker/sts/typeRelationContext.h b/checker/sts/typeRelationContext.h new file mode 100644 index 000000000..01e305011 --- /dev/null +++ b/checker/sts/typeRelationContext.h @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_TYPE_RELATION_CONTEXT_H +#define ES2PANDA_COMPILER_CHECKER_STS_TYPE_RELATION_CONTEXT_H + +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterInstantiation.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { +class STSChecker; + +class AssignmentContext { +public: + AssignmentContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target, + const lexer::SourcePosition &pos, std::initializer_list list, + TypeRelationFlag flags = TypeRelationFlag::NONE) + { + if (node->IsArrayExpression() && target->IsSTSArrayType()) { + ValidateArrayTypeInitializerByElement(relation, node->AsArrayExpression(), target->AsSTSArrayType()); + return; + } + + flags_ |= flags; + relation->SetNode(node); + + if (source->HasTypeFlag(TypeFlag::CONSTANT)) { + flags_ |= TypeRelationFlag::NARROWING; + } + + relation->SetFlags(flags_); + + if (!relation->IsAssignableTo(source, target) && !(flags_ & TypeRelationFlag::NO_THROW)) { + relation->RaiseError(list, pos); + } + + relation->SetNode(nullptr); + relation->SetFlags(TypeRelationFlag::NONE); + assignable_ = true; + } + + bool IsAssigable() const + { + return assignable_; + } + + void ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node, STSArrayType *target); + +private: + TypeRelationFlag flags_ = TypeRelationFlag::ASSIGNMENT_CONTEXT; + bool assignable_ {false}; +}; + +class InvocationContext { +public: + InvocationContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target, + const lexer::SourcePosition &pos, std::initializer_list list, + TypeRelationFlag initialFlags = TypeRelationFlag::NONE) + { + relation->SetNode(node); + + relation->SetFlags(flags_ | initialFlags); + + bool assignable = relation->IsAssignableTo(source, target); + + relation->SetNode(nullptr); + relation->SetFlags(TypeRelationFlag::NONE); + + if (!assignable) { + if (!(initialFlags & TypeRelationFlag::NO_THROW)) { + relation->RaiseError(list, pos); + } + return; + } + + invocable_ = true; + } + + bool IsInvocable() const + { + return invocable_; + } + +private: + TypeRelationFlag flags_ = TypeRelationFlag::BOXING | TypeRelationFlag::UNBOXING; + bool invocable_ {false}; +}; + +class InstantiationContext { +public: + InstantiationContext(STSChecker *checker, STSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs, + const lexer::SourcePosition &pos) + : checker_(checker), typeArgVars_(checker->Allocator()->Adapter()) + { + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + + if (type->HasObjectFlag(STSObjectFlags::CLASS)) { + typeParamDecl = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + } else { + ASSERT(type->HasObjectFlag(STSObjectFlags::INTERFACE)) + typeParamDecl = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + } + + if (ValidateTypeArguments(type, typeParamDecl, typeArgs, pos)) { + return; + } + + InstantiateType(type, typeParamDecl, typeArgs); + } + + InstantiationContext(STSChecker *checker, STSObjectType *type, ArenaVector &typeArgs) + : checker_(checker), typeArgVars_(checker->Allocator()->Adapter()) + { + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + + if (type->HasObjectFlag(STSObjectFlags::CLASS)) { + typeParamDecl = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + } else { + ASSERT(type->HasObjectFlag(STSObjectFlags::INTERFACE)) + typeParamDecl = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + } + + InstantiateType(type, typeParamDecl, typeArgs); + } + + STSObjectType *Result() + { + return result_; + } + +private: + bool ValidateTypeArguments(STSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs, const lexer::SourcePosition &pos); + void InstantiateType(STSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs); + + void InstantiateType(STSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ArenaVector &typeArgTypes); + util::StringView GetHashFromTypeArguments(ArenaVector &typeArgTypes); + + STSChecker *checker_; + ArenaVector typeArgVars_; + STSObjectType *result_ {}; +}; + +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/sts/unboxingConverter.cpp b/checker/sts/unboxingConverter.cpp new file mode 100644 index 000000000..fb0174764 --- /dev/null +++ b/checker/sts/unboxingConverter.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { + +checker::Type *UnboxingConverter::GlobalTypeFromSource(STSObjectFlags type) +{ + switch (type) { + case STSObjectFlags::BUILTIN_BOOLEAN: { + return checker_->GlobalSTSBooleanType(); + } + case STSObjectFlags::BUILTIN_BYTE: { + return checker_->GlobalByteType(); + } + case STSObjectFlags::BUILTIN_SHORT: { + return checker_->GlobalShortType(); + } + case STSObjectFlags::BUILTIN_CHAR: { + return checker_->GlobalCharType(); + } + case STSObjectFlags::BUILTIN_INT: { + return checker_->GlobalIntType(); + } + case STSObjectFlags::BUILTIN_LONG: { + return checker_->GlobalLongType(); + } + case STSObjectFlags::BUILTIN_FLOAT: { + return checker_->GlobalFloatType(); + } + case STSObjectFlags::BUILTIN_DOUBLE: { + return checker_->GlobalDoubleType(); + } + default: + return source_; + } +} + +} // namespace panda::es2panda::checker diff --git a/checker/sts/unboxingConverter.h b/checker/sts/unboxingConverter.h new file mode 100644 index 000000000..9623987c9 --- /dev/null +++ b/checker/sts/unboxingConverter.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_UNBOXING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_STS_UNBOXING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/stsObjectType.h" + +namespace panda::es2panda::checker { + +class UnboxingConverter : public TypeConverter { +public: + UnboxingConverter(STSChecker *checker, TypeRelation *relation, Type *source, Type *target) + : TypeConverter(checker, relation, target, source) + { + result_ = source_; + + if (!source_->IsSTSObjectType()) { + return; + } + + result_ = GlobalTypeFromSource(source_->AsSTSObjectType()->BuiltInKind()); + + if (relation->GetNode()) { + relation_->GetNode()->SetTsType(result_); + } + + relation_->Result(true); + } + + checker::Type *GlobalTypeFromSource(STSObjectFlags type); +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/sts/wideningConverter.cpp b/checker/sts/wideningConverter.cpp new file mode 100644 index 000000000..0c7e36c5d --- /dev/null +++ b/checker/sts/wideningConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wideningConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/sts/wideningConverter.h b/checker/sts/wideningConverter.h new file mode 100644 index 000000000..b333fd0d1 --- /dev/null +++ b/checker/sts/wideningConverter.h @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_STS_WIDENING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_STS_WIDENING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { + +class WideningConverter : public TypeConverter { +public: + explicit WideningConverter(STSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : TypeConverter(checker, relation, target, source) + { + ASSERT(relation->GetNode()); + + if (!relation_->ApplyWidening()) { + return; + } + + if (!source_->HasTypeFlag(TypeFlag::CONSTANT)) { + ApplyGlobalWidening(); + } else { + ApplyConstWidening(); + } + } + +private: + void ApplyConstWidening() + { + switch (STSChecker::STSChecker::STSType(target_)) { + case TypeFlag::SHORT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyWidening(TypeFlag::WIDENABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_FLOAT); + break; + } + case TypeFlag::DOUBLE: { + ApplyWidening(TypeFlag::WIDENABLE_TO_DOUBLE); + break; + } + default: { + break; + } + } + } + + void ApplyGlobalWidening() + { + switch (STSChecker::STSChecker::STSType(target_)) { + case TypeFlag::SHORT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_FLOAT); + break; + } + case TypeFlag::DOUBLE: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_DOUBLE); + break; + } + default: { + break; + } + } + } + + void ApplyGlobalWidening(TypeFlag flag) + { + if (!source_->HasTypeFlag(flag)) { + return; + } + + switch (STSChecker::STSChecker::STSType(source_)) { + case TypeFlag::BYTE: { + relation_->GetNode()->SetTsType(checker_->GlobalByteType()); + break; + } + case TypeFlag::SHORT: { + relation_->GetNode()->SetTsType(checker_->GlobalShortType()); + break; + } + case TypeFlag::INT: { + relation_->GetNode()->SetTsType(checker_->GlobalIntType()); + break; + } + case TypeFlag::LONG: { + relation_->GetNode()->SetTsType(checker_->GlobalLongType()); + break; + } + case TypeFlag::FLOAT: { + relation_->GetNode()->SetTsType(checker_->GlobalFloatType()); + break; + } + case TypeFlag::DOUBLE: { + relation_->GetNode()->SetTsType(checker_->GlobalDoubleType()); + break; + } + default: { + return; + } + } + + relation_->Result(true); + } + + template + void ApplyWidening(TypeFlag flag) + { + if (!source_->HasTypeFlag(flag)) { + return; + } + + switch (STSChecker::STSChecker::STSType(source_)) { + case TypeFlag::BYTE: { + ApplyWidening(); + break; + } + case TypeFlag::CHAR: { + ApplyWidening(); + break; + } + case TypeFlag::SHORT: { + ApplyWidening(); + break; + } + case TypeFlag::INT: { + ApplyWidening(); + break; + } + case TypeFlag::LONG: { + ApplyWidening(); + break; + } + case TypeFlag::FLOAT: { + ApplyWidening(); + break; + } + case TypeFlag::DOUBLE: { + ApplyWidening(); + break; + } + default: { + return; + } + } + relation_->Result(true); + } + + template + void ApplyWidening() + { + using SType = typename SourceType::UType; + using TType = typename TargetType::UType; + SType value = reinterpret_cast(source_)->GetValue(); + + relation_->GetNode()->SetTsType(checker_->Allocator()->New(static_cast(value))); + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/typescript/core/binaryLikeExpression.cpp b/checker/ts/binaryLikeExpression.cpp similarity index 85% rename from typescript/core/binaryLikeExpression.cpp rename to checker/ts/binaryLikeExpression.cpp index b5009ff7b..425a391e0 100644 --- a/typescript/core/binaryLikeExpression.cpp +++ b/checker/ts/binaryLikeExpression.cpp @@ -16,11 +16,11 @@ #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -Type *Checker::CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckBinaryOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, + ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -90,8 +90,8 @@ Type *Checker::CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Ex return resultType; } -Type *Checker::CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckPlusOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op) { if (!leftType->HasTypeFlag(TypeFlag::STRING_LIKE) && !rightType->HasTypeFlag(TypeFlag::STRING_LIKE)) { CheckNonNullType(leftType, leftExpr->Start()); @@ -122,8 +122,8 @@ Type *Checker::CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expr return resultType; } -Type *Checker::CheckCompareOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckCompareOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, + ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -138,7 +138,7 @@ Type *Checker::CheckCompareOperator(Type *leftType, Type *rightType, const ir::E return GlobalAnyType(); } -Type *Checker::CheckAndOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr) +Type *TSChecker::CheckAndOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) { CheckTruthinessOfType(leftType, leftExpr->Start()); @@ -150,7 +150,7 @@ Type *Checker::CheckAndOperator(Type *leftType, Type *rightType, const ir::Expre return leftType; } -Type *Checker::CheckOrOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr) +Type *TSChecker::CheckOrOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) { CheckTruthinessOfType(leftType, leftExpr->Start()); @@ -169,8 +169,8 @@ static bool TypeHasCallOrConstructSignatures(Type *type) (!type->AsObjectType()->CallSignatures().empty() || !type->AsObjectType()->ConstructSignatures().empty()); } -Type *Checker::CheckInstanceofExpression(Type *leftType, Type *rightType, const ir::Expression *rightExpr, - const ir::AstNode *expr) +Type *TSChecker::CheckInstanceofExpression(Type *leftType, Type *rightType, ir::Expression *rightExpr, + ir::AstNode *expr) { if (leftType->TypeFlags() != TypeFlag::ANY && IsAllTypesAssignableTo(leftType, GlobalPrimitiveType())) { ThrowTypeError({"The left-hand side of an 'instanceof' expression must be of type 'any',", @@ -188,8 +188,8 @@ Type *Checker::CheckInstanceofExpression(Type *leftType, Type *rightType, const return GlobalBooleanType(); } -Type *Checker::CheckInExpression(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr) +Type *TSChecker::CheckInExpression(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -209,8 +209,7 @@ Type *Checker::CheckInExpression(Type *leftType, Type *rightType, const ir::Expr return GlobalBooleanType(); } -void Checker::CheckAssignmentOperator(lexer::TokenType op, const ir::Expression *leftExpr, Type *leftType, - Type *valueType) +void TSChecker::CheckAssignmentOperator(lexer::TokenType op, ir::Expression *leftExpr, Type *leftType, Type *valueType) { if (IsAssignmentOperator(op)) { CheckReferenceExpression( diff --git a/typescript/core/destructuringContext.cpp b/checker/ts/destructuringContext.cpp similarity index 95% rename from typescript/core/destructuringContext.cpp rename to checker/ts/destructuringContext.cpp index 046ff5f38..8dd3b23dc 100644 --- a/typescript/core/destructuringContext.cpp +++ b/checker/ts/destructuringContext.cpp @@ -27,12 +27,12 @@ #include "plugins/ecmascript/es2panda/ir/expression.h" namespace panda::es2panda::checker { -void DestructuringContext::Prepare(const ir::Expression *typeAnnotation, const ir::Expression *initializer, +void DestructuringContext::Prepare(ir::TypeNode *typeAnnotation, ir::Expression *initializer, const lexer::SourcePosition &loc) { if (typeAnnotation != nullptr) { typeAnnotation->Check(checker_); - Type *annotationType = typeAnnotation->AsTypeNode()->GetType(checker_); + Type *annotationType = typeAnnotation->GetType(checker_); if (initializer != nullptr) { checker_->ElaborateElementwise(annotationType, initializer, loc); @@ -52,8 +52,7 @@ void DestructuringContext::Prepare(const ir::Expression *typeAnnotation, const i } } -void DestructuringContext::HandleDestructuringAssignment(const ir::Identifier *ident, Type *inferedType, - Type *defaultType) +void DestructuringContext::HandleDestructuringAssignment(ir::Identifier *ident, Type *inferedType, Type *defaultType) { if (ident->Variable() == nullptr) { checker_->ThrowTypeError({"Cannot find name '", ident->Name(), "'."}, ident->Start()); @@ -96,7 +95,7 @@ void DestructuringContext::SetInferedTypeForVariable(binder::Variable *var, Type var->SetTsType(inferedType); } -void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, const ir::ObjectExpression *obj_pattern) +void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, ir::ObjectExpression *obj_pattern) { for (const auto *sourceProp : obj_type->Properties()) { const util::StringView &sourceName = sourceProp->Name(); @@ -124,7 +123,7 @@ void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, const } } -void DestructuringContext::HandleAssignmentPattern(const ir::AssignmentExpression *assignmentPattern, Type *inferedType, +void DestructuringContext::HandleAssignmentPattern(ir::AssignmentExpression *assignmentPattern, Type *inferedType, bool validateDefault) { if (!assignmentPattern->Left()->IsArrayPattern()) { @@ -368,7 +367,7 @@ Type *ArrayDestructuringContext::GetRestType([[maybe_unused]] const lexer::Sourc return checker_->CreateUnionType(std::move(tupleUnion)); } -void ArrayDestructuringContext::HandleRest(const ir::SpreadElement *rest) +void ArrayDestructuringContext::HandleRest(ir::SpreadElement *rest) { Type *inferedRestType = GetRestType(rest->Start()); @@ -397,7 +396,7 @@ void ArrayDestructuringContext::HandleRest(const ir::SpreadElement *rest) nextContext.Start(); } -Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) +Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) { if (!convertTupleToArray_) { return type; @@ -419,7 +418,7 @@ Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir return type; } -static void SetParameterType(const ir::AstNode *parent, Type *type) +static void SetParameterType(ir::AstNode *parent, Type *type) { parent->Iterate([type](ir::AstNode *childNode) -> void { if (childNode->IsIdentifier() && childNode->AsIdentifier()->Variable() != nullptr) { @@ -434,7 +433,7 @@ static void SetParameterType(const ir::AstNode *parent, Type *type) void ArrayDestructuringContext::SetRemainingPatameterTypes() { do { - const auto *it = id_->AsArrayPattern()->Elements()[index_]; + auto *it = id_->AsArrayPattern()->Elements()[index_]; ASSERT(it); SetParameterType(it, checker_->GlobalAnyType()); } while (++index_ != id_->AsArrayPattern()->Elements().size()); @@ -448,7 +447,7 @@ void ArrayDestructuringContext::Start() util::StringView name = util::Helpers::ToStringView(checker_->Allocator(), 0); - for (const auto *it : id_->AsArrayPattern()->Elements()) { + for (auto *it : id_->AsArrayPattern()->Elements()) { if (it->IsRestElement()) { HandleRest(it->AsRestElement()); break; @@ -521,7 +520,7 @@ void ObjectDestructuringContext::ValidateInferedType() ValidateObjectLiteralType(inferedType_->AsObjectType(), id_->AsObjectPattern()); } -void ObjectDestructuringContext::HandleRest(const ir::SpreadElement *rest) +void ObjectDestructuringContext::HandleRest(ir::SpreadElement *rest) { Type *inferedRestType = GetRestType(rest->Start()); ASSERT(rest->Argument()->IsIdentifier()); @@ -577,7 +576,7 @@ Type *ObjectDestructuringContext::GetRestType([[maybe_unused]] const lexer::Sour checker_->ThrowTypeError("Rest types may only be created from object types.", loc); } -Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) +Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) { if (!convertTupleToArray_) { return type; @@ -589,7 +588,7 @@ Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const i ASSERT(node->IsProperty()); - const ir::Property *property = node->AsProperty(); + ir::Property *property = node->AsProperty(); if (property->Value()->IsArrayPattern()) { return type; @@ -641,10 +640,10 @@ void ObjectDestructuringContext::Start() ValidateInferedType(); } - for (const auto *it : id_->AsObjectPattern()->Properties()) { + for (auto *it : id_->AsObjectPattern()->Properties()) { switch (it->Type()) { case ir::AstNodeType::PROPERTY: { - const ir::Property *property = it->AsProperty(); + ir::Property *property = it->AsProperty(); if (property->IsComputed()) { // TODO(aszilagyi) diff --git a/typescript/core/destructuringContext.h b/checker/ts/destructuringContext.h similarity index 64% rename from typescript/core/destructuringContext.h rename to checker/ts/destructuringContext.h index 5e0619773..2f649e859 100644 --- a/typescript/core/destructuringContext.h +++ b/checker/ts/destructuringContext.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_TYPESCIRPT_CORE_DESTRUCTURING_CONTEXT_H -#define ES2PANDA_TYPESCIRPT_CORE_DESTRUCTURING_CONTEXT_H +#ifndef ES2PANDA_CHECKER_TS_DESTRUCTURING_CONTEXT_H +#define ES2PANDA_CHECKER_TS_DESTRUCTURING_CONTEXT_H -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" #include "plugins/ecmascript/es2panda/ir/expression.h" #include @@ -31,8 +31,8 @@ class Type; class DestructuringContext { public: - DestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + DestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : checker_(checker), id_(id), inAssignment_(inAssignment), convertTupleToArray_(convertTupleToArray) { Prepare(typeAnnotation, initializer, id->Start()); @@ -53,13 +53,11 @@ public: return inferedType_; } - void ValidateObjectLiteralType(ObjectType *obj_type, const ir::ObjectExpression *obj_pattern); - void HandleDestructuringAssignment(const ir::Identifier *ident, Type *inferedType, Type *defaultType); - void HandleAssignmentPattern(const ir::AssignmentExpression *assignmentPattern, Type *inferedType, - bool validateDefault); + void ValidateObjectLiteralType(ObjectType *obj_type, ir::ObjectExpression *obj_pattern); + void HandleDestructuringAssignment(ir::Identifier *ident, Type *inferedType, Type *defaultType); + void HandleAssignmentPattern(ir::AssignmentExpression *assignmentPattern, Type *inferedType, bool validateDefault); void SetInferedTypeForVariable(binder::Variable *var, Type *inferedType, const lexer::SourcePosition &loc); - void Prepare(const ir::Expression *typeAnnotation, const ir::Expression *initializer, - const lexer::SourcePosition &loc); + void Prepare(ir::TypeNode *typeAnnotation, ir::Expression *initializer, const lexer::SourcePosition &loc); DEFAULT_COPY_SEMANTIC(DestructuringContext); DEFAULT_MOVE_SEMANTIC(DestructuringContext); @@ -68,14 +66,14 @@ public: virtual void Start() = 0; virtual void ValidateInferedType() = 0; virtual Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) = 0; - virtual void HandleRest(const ir::SpreadElement *rest) = 0; + virtual void HandleRest(ir::SpreadElement *rest) = 0; virtual Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) = 0; - virtual Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) = 0; + virtual Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) = 0; protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - Checker *checker_; - const ir::Expression *id_; + TSChecker *checker_; + ir::Expression *id_; bool inAssignment_; bool convertTupleToArray_; Type *inferedType_ {}; @@ -87,8 +85,8 @@ protected: class ArrayDestructuringContext : public DestructuringContext { public: - ArrayDestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + ArrayDestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : DestructuringContext(checker, id, inAssignment, convertTupleToArray, typeAnnotation, initializer) { } @@ -101,9 +99,9 @@ public: void Start() override; void ValidateInferedType() override; Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) override; - void HandleRest(const ir::SpreadElement *rest) override; + void HandleRest(ir::SpreadElement *rest) override; Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) override; - Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) override; + Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) override; private: uint32_t index_ {0}; @@ -111,8 +109,8 @@ private: class ObjectDestructuringContext : public DestructuringContext { public: - ObjectDestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + ObjectDestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : DestructuringContext(checker, id, inAssignment, convertTupleToArray, typeAnnotation, initializer) { } @@ -122,9 +120,9 @@ public: void Start() override; void ValidateInferedType() override; Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) override; - void HandleRest(const ir::SpreadElement *rest) override; + void HandleRest(ir::SpreadElement *rest) override; Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) override; - Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) override; + Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) override; }; } // namespace panda::es2panda::checker diff --git a/typescript/core/function.cpp b/checker/ts/function.cpp similarity index 76% rename from typescript/core/function.cpp rename to checker/ts/function.cpp index 479384a3f..8c963f5cc 100644 --- a/typescript/core/function.cpp +++ b/checker/ts/function.cpp @@ -33,10 +33,10 @@ #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/declaration.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/core/destructuringContext.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectDescriptor.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ts/destructuringContext.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectDescriptor.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" #include #include @@ -44,11 +44,11 @@ #include namespace panda::es2panda::checker { -Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) +Type *TSChecker::HandleFunctionReturn(ir::ScriptFunction *func) { if (func->ReturnTypeAnnotation() != nullptr) { func->ReturnTypeAnnotation()->Check(this); - Type *returnType = func->ReturnTypeAnnotation()->AsTypeNode()->GetType(this); + Type *returnType = func->ReturnTypeAnnotation()->GetType(this); if (func->IsArrow() && func->Body()->IsExpression()) { ElaborateElementwise(returnType, func->Body()->AsExpression(), func->Body()->Start()); @@ -76,7 +76,7 @@ Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) return func->Body()->Check(this); } - ArenaVector returnTypes(allocator_->Adapter()); + ArenaVector returnTypes(allocator_.Adapter()); CollectTypesFromReturnStatements(func->Body(), &returnTypes); if (returnTypes.empty()) { @@ -96,7 +96,7 @@ Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) return CreateUnionType(std::move(returnTypes)); } -void Checker::ThrowReturnTypeCircularityError(const ir::ScriptFunction *func) +void TSChecker::ThrowReturnTypeCircularityError(ir::ScriptFunction *func) { if (func->ReturnTypeAnnotation() != nullptr) { ThrowTypeError("Return type annotation circularly reference itself", func->ReturnTypeAnnotation()->Start()); @@ -115,8 +115,8 @@ void Checker::ThrowReturnTypeCircularityError(const ir::ScriptFunction *func) func->Start()); } -std::tuple Checker::CheckFunctionIdentifierParameter( - const ir::Identifier *param) +std::tuple TSChecker::CheckFunctionIdentifierParameter( + ir::Identifier *param) { ASSERT(param->Variable()); binder::Variable *param_var = param->Variable(); @@ -131,11 +131,11 @@ std::tuple Checker::Chec } param->TypeAnnotation()->Check(this); - param_var->SetTsType(param->TypeAnnotation()->AsTypeNode()->GetType(this)); + param_var->SetTsType(param->TypeAnnotation()->GetType(this)); return {param_var->AsLocalVariable(), nullptr, is_optional}; } -Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpression *arrayPattern, Type *inferedType) +Type *TSChecker::CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpression *arrayPattern, Type *inferedType) { if (!inferedType->IsObjectType()) { return inferedType; @@ -148,12 +148,13 @@ Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpre return inferedType; } - TupleType *newTuple = inferedTuple->Instantiate(allocator_, relation_, globalTypes_)->AsObjectType()->AsTupleType(); + TupleType *newTuple = + inferedTuple->Instantiate(&allocator_, relation_, globalTypes_)->AsObjectType()->AsTupleType(); for (uint32_t index = inferedTuple->FixedLength(); index < arrayPattern->Elements().size(); index++) { - util::StringView memberIndex = util::Helpers::ToStringView(allocator_, index); + util::StringView memberIndex = util::Helpers::ToStringView(&allocator_, index); binder::LocalVariable *newMember = binder::Scope::CreateVar( - allocator_, memberIndex, binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); + &allocator_, memberIndex, binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); newMember->SetTsType(GlobalAnyType()); newTuple->AddProperty(newMember); } @@ -161,21 +162,20 @@ Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpre return newTuple; } -Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExpression *objectPattern, - Type *inferedType) +Type *TSChecker::CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpression *objectPattern, Type *inferedType) { if (!inferedType->IsObjectType()) { return inferedType; } - ObjectType *newObject = inferedType->Instantiate(allocator_, relation_, globalTypes_)->AsObjectType(); + ObjectType *newObject = inferedType->Instantiate(&allocator_, relation_, globalTypes_)->AsObjectType(); - for (const auto *it : objectPattern->Properties()) { + for (auto *it : objectPattern->Properties()) { if (it->IsRestElement()) { continue; } - const ir::Property *prop = it->AsProperty(); + ir::Property *prop = it->AsProperty(); binder::LocalVariable *foundVar = newObject->GetProperty(prop->Key()->AsIdentifier()->Name(), true); if (foundVar != nullptr) { @@ -187,10 +187,10 @@ Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExp } ASSERT(prop->Value()->IsAssignmentPattern()); - const ir::AssignmentExpression *assignmentPattern = prop->Value()->AsAssignmentPattern(); + ir::AssignmentExpression *assignmentPattern = prop->Value()->AsAssignmentPattern(); binder::LocalVariable *newProp = - binder::Scope::CreateVar(allocator_, prop->Key()->AsIdentifier()->Name(), + binder::Scope::CreateVar(&allocator_, prop->Key()->AsIdentifier()->Name(), binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); newProp->SetTsType(GetBaseTypeOfLiteralType(CheckTypeCached(assignmentPattern->Right()))); newObject->AddProperty(newProp); @@ -200,17 +200,17 @@ Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExp return newObject; } -std::tuple Checker::CheckFunctionAssignmentPatternParameter( - const ir::AssignmentExpression *param) +std::tuple TSChecker::CheckFunctionAssignmentPatternParameter( + ir::AssignmentExpression *param) { if (param->Left()->IsIdentifier()) { - const ir::Identifier *paramIdent = param->Left()->AsIdentifier(); + ir::Identifier *paramIdent = param->Left()->AsIdentifier(); binder::Variable *paramVar = paramIdent->Variable(); ASSERT(paramVar); if (paramIdent->TypeAnnotation() != nullptr) { paramIdent->TypeAnnotation()->Check(this); - Type *paramType = paramIdent->TypeAnnotation()->AsTypeNode()->GetType(this); + Type *paramType = paramIdent->TypeAnnotation()->GetType(this); paramVar->SetTsType(paramType); ElaborateElementwise(paramType, param->Right(), paramIdent->Start()); return {paramVar->AsLocalVariable(), nullptr, true}; @@ -227,14 +227,14 @@ std::tuple Checker::Chec auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE | CheckerStatus::IN_PARAMETER); if (param->Left()->IsArrayPattern()) { - const ir::ArrayExpression *arrayPattern = param->Left()->AsArrayPattern(); + ir::ArrayExpression *arrayPattern = param->Left()->AsArrayPattern(); auto context = ArrayDestructuringContext(this, arrayPattern, false, true, arrayPattern->TypeAnnotation(), param->Right()); context.Start(); paramType = CreateParameterTypeForArrayAssignmentPattern(arrayPattern, context.InferedType()); CreatePatternParameterName(param->Left(), ss); } else { - const ir::ObjectExpression *objectPattern = param->Left()->AsObjectPattern(); + ir::ObjectExpression *objectPattern = param->Left()->AsObjectPattern(); auto context = ObjectDestructuringContext(this, objectPattern, false, true, objectPattern->TypeAnnotation(), param->Right()); context.Start(); @@ -242,41 +242,27 @@ std::tuple Checker::Chec CreatePatternParameterName(param->Left(), ss); } - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), &allocator_); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(&allocator_, pn.View(), binder::VariableFlags::NONE, param); patternVar->SetTsType(paramType); patternVar->AddFlag(binder::VariableFlags::OPTIONAL); return {patternVar->AsLocalVariable(), nullptr, true}; } -std::tuple Checker::CheckFunctionRestParameter( - const ir::SpreadElement *param, SignatureInfo *signatureInfo) +std::tuple TSChecker::CheckFunctionRestParameter( + ir::SpreadElement *param, SignatureInfo *signatureInfo) { - const ir::Expression *typeAnnotation = nullptr; - switch (param->Argument()->Type()) { - case ir::AstNodeType::IDENTIFIER: { - typeAnnotation = param->Argument()->AsIdentifier()->TypeAnnotation(); - break; - } - case ir::AstNodeType::OBJECT_PATTERN: { - typeAnnotation = param->Argument()->AsArrayPattern()->TypeAnnotation(); - break; - } - case ir::AstNodeType::ARRAY_PATTERN: { - typeAnnotation = param->Argument()->AsObjectPattern()->TypeAnnotation(); - break; - } - default: { - UNREACHABLE(); - } + ir::TypeNode *typeAnnotation = nullptr; + if (param->Argument()) { + typeAnnotation = param->Argument()->AsAnnotatedExpression()->TypeAnnotation(); } - Type *restType = allocator_->New(GlobalAnyType()); + Type *restType = allocator_.New(GlobalAnyType()); if (typeAnnotation != nullptr) { typeAnnotation->Check(this); - restType = typeAnnotation->AsTypeNode()->GetType(this); + restType = typeAnnotation->GetType(this); if (!restType->IsArrayType()) { ThrowTypeError("A rest parameter must be of an array type", param->Start()); } @@ -284,7 +270,7 @@ std::tuple Checker::Chec switch (param->Argument()->Type()) { case ir::AstNodeType::IDENTIFIER: { - const ir::Identifier *restIdent = param->Argument()->AsIdentifier(); + ir::Identifier *restIdent = param->Argument()->AsIdentifier(); ASSERT(restIdent->Variable()); restIdent->Variable()->SetTsType(restType->AsArrayType()->ElementType()); return {nullptr, restIdent->Variable()->AsLocalVariable(), false}; @@ -314,14 +300,14 @@ std::tuple Checker::Chec } } -std::tuple Checker::CheckFunctionArrayPatternParameter( - const ir::ArrayExpression *param) +std::tuple TSChecker::CheckFunctionArrayPatternParameter( + ir::ArrayExpression *param) { std::stringstream ss; CreatePatternParameterName(param, ss); - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), &allocator_); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(&allocator_, pn.View(), binder::VariableFlags::NONE, param); if (param->TypeAnnotation() != nullptr) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); @@ -336,14 +322,14 @@ std::tuple Checker::Chec return {patternVar->AsLocalVariable(), nullptr, false}; } -std::tuple Checker::CheckFunctionObjectPatternParameter( - const ir::ObjectExpression *param) +std::tuple TSChecker::CheckFunctionObjectPatternParameter( + ir::ObjectExpression *param) { std::stringstream ss; CreatePatternParameterName(param, ss); - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), &allocator_); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(&allocator_, pn.View(), binder::VariableFlags::NONE, param); if (param->TypeAnnotation() != nullptr) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); @@ -358,13 +344,12 @@ std::tuple Checker::Chec return {patternVar->AsLocalVariable(), nullptr, false}; } -std::tuple Checker::CheckFunctionParameter( - const ir::Expression *param, SignatureInfo *signatureInfo) +std::tuple TSChecker::CheckFunctionParameter( + ir::Expression *param, SignatureInfo *signatureInfo) { - auto found = nodeCache_.find(param); - if (found != nodeCache_.end()) { - ASSERT(found->second->Variable()); - binder::Variable *var = found->second->Variable(); + if (param->TsType()) { + ASSERT(param->TsType()->Variable()); + binder::Variable *var = param->TsType()->Variable(); return {var->AsLocalVariable(), nullptr, var->HasFlag(binder::VariableFlags::OPTIONAL)}; } @@ -399,16 +384,16 @@ std::tuple Checker::Chec } if (cache) { - Type *placeholder = allocator_->New(GlobalAnyType()); + Type *placeholder = allocator_.New(GlobalAnyType()); placeholder->SetVariable(std::get<0>(result)); - nodeCache_.insert({param, placeholder}); + param->SetTsType(placeholder); } return result; } -void Checker::CheckFunctionParameterDeclarations(const ArenaVector ¶ms, - SignatureInfo *signatureInfo) +void TSChecker::CheckFunctionParameterDeclarations(const ArenaVector ¶ms, + SignatureInfo *signatureInfo) { signatureInfo->restVar = nullptr; signatureInfo->minArgCount = 0; @@ -433,14 +418,14 @@ void Checker::CheckFunctionParameterDeclarations(const ArenaVectorIsArrayPattern() || prop_value->IsObjectPattern() || (prop_value->IsAssignmentPattern() && (prop_value->AsAssignmentPattern()->Left()->IsArrayPattern() || prop_value->AsAssignmentPattern()->Left()->IsObjectPattern())); } -void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstream &ss) +void TSChecker::CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss) { switch (node->Type()) { case ir::AstNodeType::IDENTIFIER: { @@ -480,7 +465,7 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr break; } case ir::AstNodeType::PROPERTY: { - const ir::Property *prop = node->AsProperty(); + ir::Property *prop = node->AsProperty(); util::StringView propName; if (prop->Key()->IsIdentifier()) { @@ -488,7 +473,8 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr } else { switch (prop->Key()->Type()) { case ir::AstNodeType::NUMBER_LITERAL: { - propName = util::Helpers::ToStringView(allocator_, prop->Key()->AsNumberLiteral()->Number()); + propName = util::Helpers::ToStringView(&allocator_, + prop->Key()->AsNumberLiteral()->Number().GetDouble()); break; } case ir::AstNodeType::BIGINT_LITERAL: { @@ -510,14 +496,14 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr if (ShouldCreatePropertyValueName(prop->Value())) { ss << ": "; - Checker::CreatePatternParameterName(prop->Value(), ss); + TSChecker::CreatePatternParameterName(prop->Value(), ss); } break; } case ir::AstNodeType::REST_ELEMENT: { ss << "..."; - Checker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss); + TSChecker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss); break; } default: @@ -525,7 +511,7 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr } } -const ir::Statement *FindSubsequentFunctionNode(const ir::BlockStatement *block, const ir::ScriptFunction *node) +ir::Statement *FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node) { for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) { if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) { @@ -537,22 +523,21 @@ const ir::Statement *FindSubsequentFunctionNode(const ir::BlockStatement *block, return nullptr; } -void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar) +void TSChecker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar) { - const ir::ScriptFunction *bodyDeclaration = decl->Decls().back(); + ir::ScriptFunction *bodyDeclaration = decl->Decls().back(); if (bodyDeclaration->IsOverload()) { ThrowTypeError("Function implementation is missing or not immediately following the declaration.", bodyDeclaration->Id()->Start()); } - ObjectDescriptor *descWithOverload = allocator_->New(allocator_); + ObjectDescriptor *descWithOverload = allocator_.New(&allocator_); for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) { - const ir::ScriptFunction *func = *it; + ir::ScriptFunction *func = *it; ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement()); - const ir::Statement *subsequentNode = - FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func); + ir::Statement *subsequentNode = FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func); ASSERT(subsequentNode); if (!subsequentNode->IsFunctionDeclaration()) { @@ -560,7 +545,7 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin func->Id()->Start()); } - const ir::ScriptFunction *subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function(); + ir::ScriptFunction *subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function(); if (subsequentFunc->Id()->Name() != func->Id()->Name()) { ThrowTypeError("Function implementation is missing or not immediately following the declaration.", @@ -573,26 +558,25 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin ScopeContext scopeCtx(this, func->Scope()); - auto *overloadSignatureInfo = allocator_->New(allocator_); + auto *overloadSignatureInfo = allocator_.New(&allocator_); CheckFunctionParameterDeclarations(func->Params(), overloadSignatureInfo); Type *returnType = GlobalAnyType(); if (func->ReturnTypeAnnotation() != nullptr) { func->ReturnTypeAnnotation()->Check(this); - returnType = func->ReturnTypeAnnotation()->AsTypeNode()->GetType(this); + returnType = func->ReturnTypeAnnotation()->GetType(this); } - Signature *overloadSignature = allocator_->New(overloadSignatureInfo, returnType); - overloadSignature->SetNode(func); + Signature *overloadSignature = allocator_.New(overloadSignatureInfo, returnType, func); descWithOverload->callSignatures.push_back(overloadSignature); } ScopeContext scopeCtx(this, bodyDeclaration->Scope()); - auto *signatureInfo = allocator_->New(allocator_); + auto *signatureInfo = allocator_.New(&allocator_); CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo); - auto *bodyCallSignature = allocator_->New(signatureInfo, GlobalResolvingReturnType()); + auto *bodyCallSignature = allocator_.New(signatureInfo, GlobalResolvingReturnType()); if (descWithOverload->callSignatures.empty()) { Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature); @@ -603,7 +587,7 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration)); if (!descWithOverload->callSignatures.empty()) { - Type *funcType = allocator_->New(descWithOverload); + Type *funcType = allocator_.New(descWithOverload); funcType->SetVariable(funcVar); funcVar->SetTsType(funcType); @@ -618,14 +602,14 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin } } - ASSERT(iter->Node() && iter->Node()->IsScriptFunction()); + ASSERT(iter->Function()); ThrowTypeError("This overload signature is not compatible with its implementation signature", - iter->Node()->AsScriptFunction()->Id()->Start()); + iter->Function()->Id()->Start()); } } } -void Checker::CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaVector *returnTypes) +void TSChecker::CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector *returnTypes) { parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void { if (childNode->IsScriptFunction()) { @@ -647,11 +631,11 @@ void Checker::CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaV }); } -static bool SearchForReturnOrThrow(const ir::AstNode *parent) +static bool SearchForReturnOrThrow(ir::AstNode *parent) { bool found = false; - parent->Iterate([&found](const ir::AstNode *childNode) -> void { + parent->Iterate([&found](ir::AstNode *childNode) -> void { if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) { found = true; return; @@ -667,8 +651,8 @@ static bool SearchForReturnOrThrow(const ir::AstNode *parent) return found; } -void Checker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction *func, - lexer::SourcePosition lineInfo, const char *errMsg) +void TSChecker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, + lexer::SourcePosition lineInfo, const char *errMsg) { if (!SearchForReturnOrThrow(func->Body())) { ThrowTypeError(errMsg, lineInfo); @@ -677,8 +661,9 @@ void Checker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFu // noImplicitReturn compiler option for TypeScript we should update this function } -ArgRange Checker::GetArgRange(const ArenaVector &signatures, ArenaVector *potentialSignatures, - uint32_t callArgsSize, bool *haveSignatureWithRest) +ArgRange TSChecker::GetArgRange(const ArenaVector &signatures, + ArenaVector *potentialSignatures, uint32_t callArgsSize, + bool *haveSignatureWithRest) { uint32_t minArg = UINT32_MAX; uint32_t maxArg = 0; @@ -704,7 +689,7 @@ ArgRange Checker::GetArgRange(const ArenaVector &signatures, ArenaV return {minArg, maxArg}; } -bool Checker::CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError) +bool TSChecker::CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError) { for (size_t index = 0; index < args.size(); index++) { checker::Type *sigArgType = nullptr; @@ -739,14 +724,15 @@ bool Checker::CallMatchesSignature(const ArenaVector &args, Si return true; } -Type *Checker::resolveCallOrNewExpression(const ArenaVector &signatures, - ArenaVector arguments, const lexer::SourcePosition &errPos) +Type *TSChecker::resolveCallOrNewExpression(const ArenaVector &signatures, + ArenaVector arguments, + const lexer::SourcePosition &errPos) { if (signatures.empty()) { ThrowTypeError("This expression is not callable.", errPos); } - ArenaVector potentialSignatures(allocator_->Adapter()); + ArenaVector potentialSignatures(allocator_.Adapter()); bool haveSignatureWithRest = false; auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest); diff --git a/typescript/core/helpers.cpp b/checker/ts/helpers.cpp similarity index 73% rename from typescript/core/helpers.cpp rename to checker/ts/helpers.cpp index 5d57490f2..44d3bc3a6 100644 --- a/typescript/core/helpers.cpp +++ b/checker/ts/helpers.cpp @@ -21,26 +21,27 @@ #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" #include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsPropertySignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsPropertySignature.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeAliasDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeReference.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" -#include "plugins/ecmascript/es2panda/typescript/core/typeElaborationContext.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/ts/typeElaborationContext.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -void Checker::CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo) +void TSChecker::CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo) { if (type->IsVoidType()) { ThrowTypeError("An expression of type void cannot be tested for truthiness", lineInfo); } } -Type *Checker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) +Type *TSChecker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) { if (type->IsNullType()) { ThrowTypeError("Object is possibly 'null'.", lineInfo); @@ -53,7 +54,7 @@ Type *Checker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) return type; } -Type *Checker::GetBaseTypeOfLiteralType(Type *type) +Type *TSChecker::GetBaseTypeOfLiteralType(Type *type) { if (HasStatus(CheckerStatus::KEEP_LITERAL_TYPE)) { return type; @@ -77,7 +78,7 @@ Type *Checker::GetBaseTypeOfLiteralType(Type *type) if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); newConstituentTypes.reserve(constituentTypes.size()); for (auto *it : constituentTypes) { @@ -90,8 +91,8 @@ Type *Checker::GetBaseTypeOfLiteralType(Type *type) return type; } -void Checker::CheckReferenceExpression(const ir::Expression *expr, const char *invalidReferenceMsg, - const char *invalidOptionalChainMsg) +void TSChecker::CheckReferenceExpression(ir::Expression *expr, const char *invalidReferenceMsg, + const char *invalidOptionalChainMsg) { if (expr->IsIdentifier()) { const util::StringView &name = expr->AsIdentifier()->Name(); @@ -110,14 +111,14 @@ void Checker::CheckReferenceExpression(const ir::Expression *expr, const char *i } } -void Checker::CheckTestingKnownTruthyCallableOrAwaitableType([[maybe_unused]] const ir::Expression *condExpr, - [[maybe_unused]] Type *type, - [[maybe_unused]] const ir::AstNode *body) +void TSChecker::CheckTestingKnownTruthyCallableOrAwaitableType([[maybe_unused]] ir::Expression *condExpr, + [[maybe_unused]] Type *type, + [[maybe_unused]] ir::AstNode *body) { // TODO(aszilagyi) rework this } -Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) +Type *TSChecker::ExtractDefinitelyFalsyTypes(Type *type) { if (type->IsStringType()) { return GlobalEmptyStringType(); @@ -141,7 +142,7 @@ Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); newConstituentTypes.reserve(constituentTypes.size()); for (auto &it : constituentTypes) { @@ -154,12 +155,12 @@ Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) return GlobalNeverType(); } -Type *Checker::RemoveDefinitelyFalsyTypes(Type *type) +Type *TSChecker::RemoveDefinitelyFalsyTypes(Type *type) { if ((static_cast(GetFalsyFlags(type)) & static_cast(TypeFlag::DEFINITELY_FALSY)) != 0U) { if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); for (auto &it : constituentTypes) { if ((static_cast(GetFalsyFlags(it)) & static_cast(TypeFlag::DEFINITELY_FALSY)) == @@ -185,7 +186,7 @@ Type *Checker::RemoveDefinitelyFalsyTypes(Type *type) return type; } -TypeFlag Checker::GetFalsyFlags(Type *type) +TypeFlag TSChecker::GetFalsyFlags(Type *type) { if (type->IsStringLiteralType()) { return type->AsStringLiteralType()->Value().Empty() ? TypeFlag::STRING_LITERAL : TypeFlag::NONE; @@ -217,11 +218,11 @@ TypeFlag Checker::GetFalsyFlags(Type *type) return static_cast(type->TypeFlags() & TypeFlag::POSSIBLY_FALSY); } -bool Checker::IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::IsVariableUsedInConditionBody(ir::AstNode *parent, binder::Variable *searchVar) { bool found = false; - parent->Iterate([this, searchVar, &found](const ir::AstNode *childNode) -> void { + parent->Iterate([this, searchVar, &found](ir::AstNode *childNode) -> void { binder::Variable *resultVar = nullptr; if (childNode->IsIdentifier()) { binder::ScopeFindResult result = scope_->Find(childNode->AsIdentifier()->Name()); @@ -242,11 +243,11 @@ bool Checker::IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::V return found; } -bool Checker::FindVariableInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::FindVariableInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar) { bool found = false; - parent->Iterate([this, searchVar, &found](const ir::AstNode *childNode) -> void { + parent->Iterate([this, searchVar, &found](ir::AstNode *childNode) -> void { if (childNode->IsIdentifier()) { binder::ScopeFindResult result = scope_->Find(childNode->AsIdentifier()->Name()); ASSERT(result.variable); @@ -262,7 +263,7 @@ bool Checker::FindVariableInBinaryExpressionChain(const ir::AstNode *parent, bin return found; } -bool Checker::IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::IsVariableUsedInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar) { while (parent->IsBinaryExpression() && parent->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { @@ -276,7 +277,8 @@ bool Checker::IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, b return false; } -void Checker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, lexer::SourcePosition lineInfo) +void TSChecker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, + lexer::SourcePosition lineInfo) { if (!HasStatus(CheckerStatus::IN_CONST_CONTEXT)) { ThrowTypeError({"operator ", op, " cannot be applied to types ", leftType, " and ", AsSrc(rightType)}, @@ -286,7 +288,7 @@ void Checker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *ri ThrowTypeError({"operator ", op, " cannot be applied to types ", leftType, " and ", rightType}, lineInfo); } -void Checker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType) +void TSChecker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType) { if (isAsSrcLeftType || !target->HasTypeFlag(TypeFlag::LITERAL)) { ThrowTypeError({"Type '", AsSrc(source), "' is not assignable to type '", target, "'."}, lineInfo); @@ -295,11 +297,11 @@ void Checker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosi ThrowTypeError({"Type '", source, "' is not assignable to type '", target, "'."}, lineInfo); } -Type *Checker::GetUnaryResultType(Type *operandType) +Type *TSChecker::GetUnaryResultType(Type *operandType) { - if (checker::Checker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) { + if (checker::TSChecker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) { if (operandType->HasTypeFlag(checker::TypeFlag::UNION_OR_INTERSECTION) && - checker::Checker::MaybeTypeOfKind(operandType, checker::TypeFlag::NUMBER_LIKE)) { + checker::TSChecker::MaybeTypeOfKind(operandType, checker::TypeFlag::NUMBER_LIKE)) { return GlobalNumberOrBigintType(); } @@ -309,7 +311,7 @@ Type *Checker::GetUnaryResultType(Type *operandType) return GlobalNumberType(); } -void Checker::ElaborateElementwise(Type *targetType, const ir::Expression *sourceNode, const lexer::SourcePosition &pos) +void TSChecker::ElaborateElementwise(Type *targetType, ir::Expression *sourceNode, const lexer::SourcePosition &pos) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE | CheckerStatus::KEEP_LITERAL_TYPE); @@ -332,7 +334,7 @@ void Checker::ElaborateElementwise(Type *targetType, const ir::Expression *sourc ThrowAssignmentError(sourceType, targetType, pos); } -void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *declarator) +void TSChecker::InferSimpleVariableDeclaratorType(ir::VariableDeclarator *declarator) { ASSERT(declarator->Id()->IsIdentifier()); @@ -340,7 +342,7 @@ void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *de ASSERT(var); if (declarator->Id()->AsIdentifier()->TypeAnnotation() != nullptr) { - var->SetTsType(declarator->Id()->AsIdentifier()->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(declarator->Id()->AsIdentifier()->TypeAnnotation()->GetType(this)); return; } @@ -353,20 +355,19 @@ void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *de declarator->Id()->Start()); } -Type *Checker::GetTypeOfVariable(binder::Variable *var) +Type *TSChecker::GetTypeOfVariable(binder::Variable *var) { if (var->TsType() != nullptr) { return var->TsType(); } - const binder::Decl *decl = var->Declaration(); + binder::Decl *decl = var->Declaration(); - if (!typeStack_.insert(decl->Node()).second) { - ThrowTypeError({"'", var->Name(), - "' is referenced directly or indirectly in its " - "own initializer ot type annotation."}, - decl->Node()->Start()); - } + TypeStackElement tse(this, decl->Node(), + {"'", var->Name(), + "' is referenced directly or indirectly in its " + "own initializer ot type annotation."}, + decl->Node()->Start()); switch (decl->Type()) { case binder::DeclType::CONST: @@ -380,7 +381,8 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) [[fallthrough]]; } case binder::DeclType::VAR: { - const ir::AstNode *declarator = FindAncestorGivenByType(decl->Node(), ir::AstNodeType::VARIABLE_DECLARATOR); + ir::AstNode *declarator = + util::Helpers::FindAncestorGivenByType(decl->Node(), ir::AstNodeType::VARIABLE_DECLARATOR); ASSERT(declarator); if (declarator->AsVariableDeclarator()->Id()->IsIdentifier()) { @@ -392,12 +394,12 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) break; } case binder::DeclType::PROPERTY: { - var->SetTsType(decl->Node()->AsTSPropertySignature()->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(decl->Node()->AsTSPropertySignature()->TypeAnnotation()->GetType(this)); break; } case binder::DeclType::METHOD: { - auto *signatureInfo = allocator_->New(allocator_); - auto *callSignature = allocator_->New(signatureInfo, GlobalAnyType()); + auto *signatureInfo = allocator_.New(&allocator_); + auto *callSignature = allocator_.New(signatureInfo, GlobalAnyType()); var->SetTsType(CreateFunctionTypeWithSignature(callSignature)); break; } @@ -407,13 +409,13 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) break; } case binder::DeclType::PARAM: { - const ir::AstNode *declaration = FindAncestorUntilGivenType(decl->Node(), ir::AstNodeType::SCRIPT_FUNCTION); + ir::AstNode *declaration = FindAncestorUntilGivenType(decl->Node(), ir::AstNodeType::SCRIPT_FUNCTION); if (declaration->IsIdentifier()) { - const ir::Identifier *ident = declaration->AsIdentifier(); + auto *ident = declaration->AsIdentifier(); if (ident->TypeAnnotation() != nullptr) { ASSERT(ident->Variable() == var); - var->SetTsType(ident->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(ident->TypeAnnotation()->GetType(this)); break; } @@ -421,11 +423,11 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) } if (declaration->IsAssignmentPattern() && declaration->AsAssignmentPattern()->Left()->IsIdentifier()) { - const ir::Identifier *ident = declaration->AsAssignmentPattern()->Left()->AsIdentifier(); + ir::Identifier *ident = declaration->AsAssignmentPattern()->Left()->AsIdentifier(); if (ident->TypeAnnotation() != nullptr) { ASSERT(ident->Variable() == var); - var->SetTsType(ident->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(ident->TypeAnnotation()->GetType(this)); break; } @@ -458,18 +460,16 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) } } - typeStack_.erase(decl->Node()); return var->TsType(); } -Type *Checker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] const ir::TSTypeReference *node, - binder::Variable *var) +Type *TSChecker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] ir::TSTypeReference *node, binder::Variable *var) { Type *resolvedType = var->TsType(); if (resolvedType == nullptr) { - ObjectDescriptor *desc = allocator_->New(allocator_); - resolvedType = allocator_->New(allocator_, var->Name(), desc); + ObjectDescriptor *desc = allocator_.New(&allocator_); + resolvedType = allocator_.New(&allocator_, var->Name(), desc); resolvedType->SetVariable(var); var->SetTsType(resolvedType); } @@ -477,27 +477,25 @@ Type *Checker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] const ir::T return resolvedType; } -Type *Checker::GetTypeFromTypeAliasReference(const ir::TSTypeReference *node, binder::Variable *var) +Type *TSChecker::GetTypeFromTypeAliasReference(ir::TSTypeReference *node, binder::Variable *var) { Type *resolvedType = var->TsType(); - if (resolvedType == nullptr) { - if (!typeStack_.insert(var).second) { - ThrowTypeError({"Type alias ", var->Name(), " circularly refences itself"}, node->Start()); - } + if (resolvedType != nullptr) { + return resolvedType; + } - ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSTypeAliasDeclaration()); - const ir::TSTypeAliasDeclaration *declaration = var->Declaration()->Node()->AsTSTypeAliasDeclaration(); - resolvedType = declaration->TypeAnnotation()->AsTypeNode()->GetType(this); - var->SetTsType(resolvedType); + TypeStackElement tse(this, var, {"Type alias ", var->Name(), " circularly refences itself"}, node->Start()); - typeStack_.erase(var); - } + ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSTypeAliasDeclaration()); + ir::TSTypeAliasDeclaration *declaration = var->Declaration()->Node()->AsTSTypeAliasDeclaration(); + resolvedType = declaration->TypeAnnotation()->GetType(this); + var->SetTsType(resolvedType); return resolvedType; } -Type *Checker::GetTypeReferenceType(const ir::TSTypeReference *node, binder::Variable *var) +Type *TSChecker::GetTypeReferenceType(ir::TSTypeReference *node, binder::Variable *var) { ASSERT(var->Declaration()); binder::Decl *decl = var->Declaration(); diff --git a/typescript/core/object.cpp b/checker/ts/object.cpp similarity index 78% rename from typescript/core/object.cpp rename to checker/ts/object.cpp index d25b48d4f..cd4f1c586 100644 --- a/typescript/core/object.cpp +++ b/checker/ts/object.cpp @@ -22,10 +22,10 @@ #include "plugins/ecmascript/es2panda/ir/base/property.h" #include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsIndexSignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsMethodSignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsPropertySignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsIndexSignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsPropertySignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeLiteral.h" #include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" @@ -34,11 +34,11 @@ #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/binder/scope.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" namespace panda::es2panda::checker { -void Checker::CheckIndexConstraints(Type *type) +void TSChecker::CheckIndexConstraints(Type *type) { if (!type->IsObjectType()) { return; @@ -80,7 +80,7 @@ void Checker::CheckIndexConstraints(Type *type) } } -void Checker::ResolveStructuredTypeMembers(Type *type) +void TSChecker::ResolveStructuredTypeMembers(Type *type) { if (type->IsObjectType()) { ObjectType *obj_type = type->AsObjectType(); @@ -102,17 +102,17 @@ void Checker::ResolveStructuredTypeMembers(Type *type) } } -void Checker::ResolveUnionTypeMembers(UnionType *type) +void TSChecker::ResolveUnionTypeMembers(UnionType *type) { if (type->MergedObjectType() != nullptr) { return; } - ObjectDescriptor *desc = allocator_->New(allocator_); - ArenaVector stringInfoTypes(allocator_->Adapter()); - ArenaVector numberInfoTypes(allocator_->Adapter()); - ArenaVector callSignatures(allocator_->Adapter()); - ArenaVector constructSignatures(allocator_->Adapter()); + ObjectDescriptor *desc = allocator_.New(&allocator_); + ArenaVector stringInfoTypes(allocator_.Adapter()); + ArenaVector numberInfoTypes(allocator_.Adapter()); + ArenaVector callSignatures(allocator_.Adapter()); + ArenaVector constructSignatures(allocator_.Adapter()); for (auto *it : type->AsUnionType()->ConstituentTypes()) { if (!it->IsObjectType()) { @@ -147,19 +147,19 @@ void Checker::ResolveUnionTypeMembers(UnionType *type) desc->constructSignatures = constructSignatures; if (!stringInfoTypes.empty()) { - desc->stringIndexInfo = allocator_->New(CreateUnionType(std::move(stringInfoTypes)), "x", false); + desc->stringIndexInfo = allocator_.New(CreateUnionType(std::move(stringInfoTypes)), "x", false); } if (!numberInfoTypes.empty()) { - desc->numberIndexInfo = allocator_->New(CreateUnionType(std::move(numberInfoTypes)), "x", false); + desc->numberIndexInfo = allocator_.New(CreateUnionType(std::move(numberInfoTypes)), "x", false); } - ObjectType *merged_type = allocator_->New(desc); + ObjectType *merged_type = allocator_.New(desc); merged_type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); type->SetMergedObjectType(merged_type); } -void Checker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) +void TSChecker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) { return; @@ -171,16 +171,16 @@ void Checker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); } -void Checker::ResolveObjectTypeMembers(ObjectType *type) +void TSChecker::ResolveObjectTypeMembers(ObjectType *type) { if (!type->IsObjectLiteralType() || type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) { return; } ASSERT(type->Variable() && type->Variable()->Declaration()->Node()->IsTSTypeLiteral()); - const auto *typeLiteral = type->Variable()->Declaration()->Node()->AsTSTypeLiteral(); - ArenaVector signatureDeclarations(allocator_->Adapter()); - ArenaVector indexDeclarations(allocator_->Adapter()); + auto *typeLiteral = type->Variable()->Declaration()->Node()->AsTSTypeLiteral(); + ArenaVector signatureDeclarations(allocator_.Adapter()); + ArenaVector indexDeclarations(allocator_.Adapter()); for (auto *it : typeLiteral->Members()) { ResolvePropertiesOfObjectType(type, it, signatureDeclarations, indexDeclarations, false); @@ -192,10 +192,9 @@ void Checker::ResolveObjectTypeMembers(ObjectType *type) ResolveIndexInfosOfObjectType(type, indexDeclarations); } -void Checker::ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expression *member, - ArenaVector &signatureDeclarations, - ArenaVector &indexDeclarations, - bool isInterface) +void TSChecker::ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member, + ArenaVector &signatureDeclarations, + ArenaVector &indexDeclarations, bool isInterface) { if (member->IsTSPropertySignature()) { binder::Variable *prop = member->AsTSPropertySignature()->Variable(); @@ -228,8 +227,8 @@ void Checker::ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expressi indexDeclarations.push_back(member->AsTSIndexSignature()); } -void Checker::ResolveSignaturesOfObjectType(ObjectType *type, - ArenaVector &signatureDeclarations) +void TSChecker::ResolveSignaturesOfObjectType(ObjectType *type, + ArenaVector &signatureDeclarations) { for (auto *it : signatureDeclarations) { Type *placeholderObj = it->Check(this); @@ -243,8 +242,7 @@ void Checker::ResolveSignaturesOfObjectType(ObjectType *type, type->AddConstructSignature(placeholderObj->AsObjectType()->ConstructSignatures()[0]); } } -void Checker::ResolveIndexInfosOfObjectType(ObjectType *type, - ArenaVector &indexDeclarations) +void TSChecker::ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations) { for (auto *it : indexDeclarations) { Type *placeholderObj = it->Check(this); @@ -270,8 +268,8 @@ void Checker::ResolveIndexInfosOfObjectType(ObjectType *type, } } -binder::Variable *Checker::GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial, - binder::VariableFlags propagateFlags) +binder::Variable *TSChecker::GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial, + binder::VariableFlags propagateFlags) { if (type->IsObjectType()) { ResolveObjectTypeMembers(type->AsObjectType()); @@ -285,8 +283,8 @@ binder::Variable *Checker::GetPropertyOfType(Type *type, const util::StringView return nullptr; } -binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, - binder::VariableFlags propagateFlags) +binder::Variable *TSChecker::GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, + binder::VariableFlags propagateFlags) { auto found = type->CachedSyntheticPropertis().find(name); @@ -295,7 +293,7 @@ binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::S } binder::VariableFlags flags = binder::VariableFlags::PROPERTY; - ArenaVector collectedTypes(allocator_->Adapter()); + ArenaVector collectedTypes(allocator_.Adapter()); for (auto *it : type->ConstituentTypes()) { binder::Variable *prop = GetPropertyOfType(it, name); @@ -341,17 +339,16 @@ binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::S return nullptr; } - binder::Variable *syntheticProp = binder::Scope::CreateVar(allocator_, name, flags, nullptr); + binder::Variable *syntheticProp = binder::Scope::CreateVar(&allocator_, name, flags, nullptr); syntheticProp->SetTsType(CreateUnionType(std::move(collectedTypes))); type->CachedSyntheticPropertis().insert({name, syntheticProp}); return syntheticProp; } -Type *Checker::CheckComputedPropertyName(const ir::Expression *key) +Type *TSChecker::CheckComputedPropertyName(ir::Expression *key) { - auto found = nodeCache_.find(key); - if (found != nodeCache_.end()) { - return found->second; + if (key->TsType()) { + return key->TsType(); } Type *keyType = key->Check(this); @@ -364,11 +361,11 @@ Type *Checker::CheckComputedPropertyName(const ir::Expression *key) key->Start()); } - nodeCache_.insert({key, keyType}); + key->SetTsType(keyType); return keyType; } -IndexInfo *Checker::GetApplicableIndexInfo(Type *type, Type *indexType) +IndexInfo *TSChecker::GetApplicableIndexInfo(Type *type, Type *indexType) { ResolveStructuredTypeMembers(type); bool getNumberInfo = indexType->HasTypeFlag(TypeFlag::NUMBER_LIKE); @@ -394,7 +391,7 @@ IndexInfo *Checker::GetApplicableIndexInfo(Type *type, Type *indexType) return nullptr; } -Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) +Type *TSChecker::GetPropertyTypeForIndexType(Type *type, Type *indexType) { if (type->IsArrayType()) { return type->AsArrayType()->ElementType(); @@ -407,7 +404,7 @@ Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) prop = GetPropertyOfType(type, indexType->AsStringLiteralType()->Value()); } else { util::StringView prop_name = - util::Helpers::ToStringView(allocator_, indexType->AsNumberLiteralType()->Value()); + util::Helpers::ToStringView(&allocator_, indexType->AsNumberLiteralType()->Value()); prop = GetPropertyOfType(type, prop_name); } @@ -439,7 +436,7 @@ Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) return nullptr; } -ArenaVector Checker::GetBaseTypes(InterfaceType *type) +ArenaVector TSChecker::GetBaseTypes(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES)) { return type->Bases(); @@ -448,18 +445,16 @@ ArenaVector Checker::GetBaseTypes(InterfaceType *type) ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl()); binder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl(); - if (!typeStack_.insert(type).second) { - ThrowTypeError({"Type ", type->Name(), " recursively references itself as a base type."}, - decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); - } + TypeStackElement tse(this, type, {"Type ", type->Name(), " recursively references itself as a base type."}, + decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); for (const auto *declaration : decl->Decls()) { if (declaration->Extends().empty()) { continue; } - for (const auto *extends : declaration->Extends()) { - Type *baseType = extends->Expr()->AsTypeNode()->GetType(this); + for (auto *extends : declaration->Extends()) { + Type *baseType = extends->Expr()->GetType(this); if (!baseType->HasTypeFlag(TypeFlag::OBJECT | TypeFlag::NON_PRIMITIVE | TypeFlag::ANY)) { ThrowTypeError( @@ -497,11 +492,10 @@ ArenaVector Checker::GetBaseTypes(InterfaceType *type) } type->AddObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES); - typeStack_.erase(type); return type->Bases(); } -void Checker::ResolveDeclaredMembers(InterfaceType *type) +void TSChecker::ResolveDeclaredMembers(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_DECLARED_MEMBERS)) { return; @@ -510,11 +504,11 @@ void Checker::ResolveDeclaredMembers(InterfaceType *type) ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl()); binder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl(); - ArenaVector signatureDeclarations(allocator_->Adapter()); - ArenaVector indexDeclarations(allocator_->Adapter()); + ArenaVector signatureDeclarations(allocator_.Adapter()); + ArenaVector indexDeclarations(allocator_.Adapter()); for (const auto *declaration : decl->Decls()) { - for (const auto *member : declaration->Body()->Body()) { + for (auto *member : declaration->Body()->Body()) { ResolvePropertiesOfObjectType(type, member, signatureDeclarations, indexDeclarations, true); } @@ -525,8 +519,8 @@ void Checker::ResolveDeclaredMembers(InterfaceType *type) } } -bool Checker::ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, - const lexer::SourcePosition &locInfo) +bool TSChecker::ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, + const lexer::SourcePosition &locInfo) { if (prop->HasFlag(binder::VariableFlags::COMPUTED)) { return true; diff --git a/typescript/core/typeCreation.cpp b/checker/ts/typeCreation.cpp similarity index 50% rename from typescript/core/typeCreation.cpp rename to checker/ts/typeCreation.cpp index dde86e22d..fdde6075c 100644 --- a/typescript/core/typeCreation.cpp +++ b/checker/ts/typeCreation.cpp @@ -13,49 +13,49 @@ * limitations under the License. */ -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" namespace panda::es2panda::checker { -Type *Checker::CreateNumberLiteralType(double value) +Type *TSChecker::CreateNumberLiteralType(double value) { auto search = numberLiteralMap_.find(value); if (search != numberLiteralMap_.end()) { return search->second; } - auto *newNumLiteralType = allocator_->New(value); + auto *newNumLiteralType = allocator_.New(value); numberLiteralMap_.insert({value, newNumLiteralType}); return newNumLiteralType; } -Type *Checker::CreateBigintLiteralType(const util::StringView &str, bool negative) +Type *TSChecker::CreateBigintLiteralType(const util::StringView &str, bool negative) { auto search = bigintLiteralMap_.find(str); if (search != bigintLiteralMap_.end()) { return search->second; } - auto *newBigiLiteralType = allocator_->New(str, negative); + auto *newBigiLiteralType = allocator_.New(str, negative); bigintLiteralMap_.insert({str, newBigiLiteralType}); return newBigiLiteralType; } -Type *Checker::CreateStringLiteralType(const util::StringView &str) +Type *TSChecker::CreateStringLiteralType(const util::StringView &str) { auto search = stringLiteralMap_.find(str); if (search != stringLiteralMap_.end()) { return search->second; } - auto *newStrLiteralType = allocator_->New(str); + auto *newStrLiteralType = allocator_.New(str); stringLiteralMap_.insert({str, newStrLiteralType}); return newStrLiteralType; } -Type *Checker::CreateUnionType(std::initializer_list constituentTypes) +Type *TSChecker::CreateUnionType(std::initializer_list constituentTypes) { - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); for (auto *it : constituentTypes) { newConstituentTypes.push_back(it); @@ -64,9 +64,9 @@ Type *Checker::CreateUnionType(std::initializer_list constituentTypes) return CreateUnionType(std::move(newConstituentTypes)); } -Type *Checker::CreateUnionType(ArenaVector &constituentTypes) +Type *TSChecker::CreateUnionType(ArenaVector &constituentTypes) { - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); for (auto *it : constituentTypes) { if (it->IsUnionType()) { @@ -86,18 +86,18 @@ Type *Checker::CreateUnionType(ArenaVector &constituentTypes) return newConstituentTypes[0]; } - auto *newUnionType = allocator_->New(newConstituentTypes); + auto *newUnionType = allocator_.New(newConstituentTypes); return UnionType::HandleUnionType(newUnionType, globalTypes_); } -Type *Checker::CreateUnionType(ArenaVector &&constituentTypes) +Type *TSChecker::CreateUnionType(ArenaVector &&constituentTypes) { if (constituentTypes.empty()) { return nullptr; } - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); for (auto *it : constituentTypes) { if (it->IsUnionType()) { @@ -117,57 +117,57 @@ Type *Checker::CreateUnionType(ArenaVector &&constituentTypes) return newConstituentTypes[0]; } - auto *newUnionType = allocator_->New(std::move(newConstituentTypes)); + auto *newUnionType = allocator_.New(std::move(newConstituentTypes)); return UnionType::HandleUnionType(newUnionType, globalTypes_); } -Type *Checker::CreateObjectTypeWithCallSignature(Signature *callSignature) +Type *TSChecker::CreateObjectTypeWithCallSignature(Signature *callSignature) { - auto *objType = allocator_->New(allocator_->New(allocator_)); + auto *objType = allocator_.New(allocator_.New(&allocator_)); objType->AddCallSignature(callSignature); return objType; } -Type *Checker::CreateObjectTypeWithConstructSignature(Signature *constructSignature) +Type *TSChecker::CreateObjectTypeWithConstructSignature(Signature *constructSignature) { - auto *objType = allocator_->New(allocator_->New(allocator_)); + auto *objType = allocator_.New(allocator_.New(&allocator_)); objType->AddConstructSignature(constructSignature); return objType; } -Type *Checker::CreateFunctionTypeWithSignature(Signature *callSignature) +Type *TSChecker::CreateFunctionTypeWithSignature(Signature *callSignature) { - auto *funcObjType = allocator_->New(allocator_->New(allocator_)); + auto *funcObjType = allocator_.New(allocator_.New(&allocator_)); funcObjType->AddCallSignature(callSignature); return funcObjType; } -Type *Checker::CreateConstructorTypeWithSignature(Signature *constructSignature) +Type *TSChecker::CreateConstructorTypeWithSignature(Signature *constructSignature) { - auto *constructObjType = allocator_->New(allocator_->New(allocator_)); + auto *constructObjType = allocator_.New(allocator_.New(&allocator_)); constructObjType->AddConstructSignature(constructSignature); return constructObjType; } -Type *Checker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, - ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly) +Type *TSChecker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, + ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly) { - desc->stringIndexInfo = allocator_->New(GlobalAnyType(), "x", readonly); - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); + desc->stringIndexInfo = allocator_.New(GlobalAnyType(), "x", readonly); + return allocator_.New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); } -Type *Checker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, - ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly, - NamedTupleMemberPool &&namedMembers) +Type *TSChecker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, + ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly, + NamedTupleMemberPool &&namedMembers) { - desc->stringIndexInfo = allocator_->New(GlobalAnyType(), "x", readonly); + desc->stringIndexInfo = allocator_.New(GlobalAnyType(), "x", readonly); if (!namedMembers.empty()) { - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, - readonly, std::move(namedMembers)); + return allocator_.New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly, + std::move(namedMembers)); } - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); + return allocator_.New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); } } // namespace panda::es2panda::checker diff --git a/typescript/core/typeElaborationContext.cpp b/checker/ts/typeElaborationContext.cpp similarity index 94% rename from typescript/core/typeElaborationContext.cpp rename to checker/ts/typeElaborationContext.cpp index cc448257a..ee616ad67 100644 --- a/typescript/core/typeElaborationContext.cpp +++ b/checker/ts/typeElaborationContext.cpp @@ -26,7 +26,7 @@ #include "plugins/ecmascript/es2panda/ir/base/property.h" namespace panda::es2panda::checker { -Type *ElaborationContext::GetBestMatchingType(Type *indexType, const ir::Expression *sourceNode) +Type *ElaborationContext::GetBestMatchingType(Type *indexType, ir::Expression *sourceNode) { ArenaVector bestMatchingType(checker_->Allocator()->Adapter()); Type *sourceType = sourceNode != nullptr ? checker_->CheckTypeCached(sourceNode) : checker_->GlobalAnyType(); @@ -105,7 +105,7 @@ void ObjectElaborationContext::Start() continue; } - const ir::Property *prop = it->AsProperty(); + ir::Property *prop = it->AsProperty(); Type *propKeyType = nullptr; if (prop->IsComputed()) { @@ -117,8 +117,8 @@ void ObjectElaborationContext::Start() break; } case ir::AstNodeType::NUMBER_LITERAL: { - propKeyType = - checker_->Allocator()->New(prop->Key()->AsNumberLiteral()->Number()); + propKeyType = checker_->Allocator()->New( + prop->Key()->AsNumberLiteral()->Number().GetDouble()); break; } case ir::AstNodeType::STRING_LITERAL: { diff --git a/typescript/core/typeElaborationContext.h b/checker/ts/typeElaborationContext.h similarity index 76% rename from typescript/core/typeElaborationContext.h rename to checker/ts/typeElaborationContext.h index 4dc247ee4..df8925df2 100644 --- a/typescript/core/typeElaborationContext.h +++ b/checker/ts/typeElaborationContext.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_TYPESCIRPT_CORE_TYPE_ELABORATION_CONTEXT_H -#define ES2PANDA_TYPESCIRPT_CORE_TYPE_ELABORATION_CONTEXT_H +#ifndef ES2PANDA_CHECKER_TS_TYPE_ELABORATION_CONTEXT_H +#define ES2PANDA_CHECKER_TS_TYPE_ELABORATION_CONTEXT_H -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" #include "plugins/ecmascript/es2panda/ir/expression.h" #include @@ -31,7 +31,7 @@ class Type; class ElaborationContext { public: - ElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : checker_(checker), targetType_(targetType), @@ -45,14 +45,14 @@ public: virtual void Start() = 0; virtual void RemoveUnnecessaryTypes() = 0; - Type *GetBestMatchingType(Type *indexType, const ir::Expression *sourceNode); + Type *GetBestMatchingType(Type *indexType, ir::Expression *sourceNode); protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - Checker *checker_; + TSChecker *checker_; Type *targetType_; Type *sourceType_; - const ir::Expression *sourceNode_; + ir::Expression *sourceNode_; const lexer::SourcePosition startPos_; ArenaVector potentialTypes_; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -60,7 +60,7 @@ protected: class ArrayElaborationContext : public ElaborationContext { public: - ArrayElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ArrayElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : ElaborationContext(checker, targetType, sourceType, sourceNode, startPos) { @@ -75,7 +75,7 @@ private: class ObjectElaborationContext : public ElaborationContext { public: - ObjectElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ObjectElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : ElaborationContext(checker, targetType, sourceType, sourceNode, startPos) { diff --git a/typescript/core/util.cpp b/checker/ts/util.cpp similarity index 76% rename from typescript/core/util.cpp rename to checker/ts/util.cpp index 779729f20..0d6f24ba6 100644 --- a/typescript/core/util.cpp +++ b/checker/ts/util.cpp @@ -19,23 +19,12 @@ #include "plugins/ecmascript/es2panda/ir/expressions/templateLiteral.h" #include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -const ir::TSQualifiedName *Checker::ResolveLeftMostQualifiedName(const ir::TSQualifiedName *qualifiedName) +ir::MemberExpression *TSChecker::ResolveLeftMostMemberExpression(ir::MemberExpression *expr) { - const ir::TSQualifiedName *iter = qualifiedName; - - while (iter->Left()->IsTSQualifiedName()) { - iter = iter->Left()->AsTSQualifiedName(); - } - - return iter; -} - -const ir::MemberExpression *Checker::ResolveLeftMostMemberExpression(const ir::MemberExpression *expr) -{ - const ir::MemberExpression *iter = expr; + ir::MemberExpression *iter = expr; while (iter->Object()->IsMemberExpression()) { iter = iter->Object()->AsMemberExpression(); @@ -44,9 +33,9 @@ const ir::MemberExpression *Checker::ResolveLeftMostMemberExpression(const ir::M return iter; } -bool Checker::InAssignment(const ir::AstNode *node) +bool TSChecker::InAssignment(ir::AstNode *node) { - const ir::AstNode *parent = node; + ir::AstNode *parent = node; while (parent->Parent() != nullptr) { if (parent->Parent()->IsAssignmentExpression()) { @@ -54,7 +43,7 @@ bool Checker::InAssignment(const ir::AstNode *node) } if (parent->Parent()->IsBinaryExpression()) { - const ir::BinaryExpression *binaryExpr = parent->Parent()->AsBinaryExpression(); + ir::BinaryExpression *binaryExpr = parent->Parent()->AsBinaryExpression(); return IsAssignmentOperator(binaryExpr->OperatorType()) && binaryExpr->Left() == parent; } @@ -67,7 +56,7 @@ bool Checker::InAssignment(const ir::AstNode *node) return false; } -bool Checker::IsAssignmentOperator(lexer::TokenType op) +bool TSChecker::IsAssignmentOperator(lexer::TokenType op) { switch (op) { case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: @@ -91,7 +80,7 @@ bool Checker::IsAssignmentOperator(lexer::TokenType op) } } -bool Checker::IsLiteralType(const Type *type) +bool TSChecker::IsLiteralType(const Type *type) { if (type->IsBooleanType()) { return true; @@ -109,23 +98,7 @@ bool Checker::IsLiteralType(const Type *type) return type->HasTypeFlag(TypeFlag::UNIT); } -const ir::AstNode *Checker::FindAncestorGivenByType(const ir::AstNode *node, ir::AstNodeType type) -{ - node = node->Parent(); - - while (node->Type() != type) { - if (node->Parent() != nullptr) { - node = node->Parent(); - continue; - } - - return nullptr; - } - - return node; -} - -const ir::AstNode *Checker::FindAncestorUntilGivenType(const ir::AstNode *node, ir::AstNodeType stop) +ir::AstNode *TSChecker::FindAncestorUntilGivenType(ir::AstNode *node, ir::AstNodeType stop) { while (node->Parent()->Type() != stop) { if (node->Parent() != nullptr) { @@ -139,7 +112,7 @@ const ir::AstNode *Checker::FindAncestorUntilGivenType(const ir::AstNode *node, return node; } -bool Checker::MaybeTypeOfKind(const Type *type, TypeFlag flags) +bool TSChecker::MaybeTypeOfKind(const Type *type, TypeFlag flags) { if (type->HasTypeFlag(flags)) { return true; @@ -159,7 +132,7 @@ bool Checker::MaybeTypeOfKind(const Type *type, TypeFlag flags) return false; } -bool Checker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) +bool TSChecker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) { if (type->IsObjectType() && type->AsObjectType()->Kind() == kind) { return true; @@ -179,7 +152,7 @@ bool Checker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) return false; } -bool Checker::IsConstantMemberAccess(const ir::Expression *expr) +bool TSChecker::IsConstantMemberAccess(ir::Expression *expr) { switch (expr->Type()) { case ir::AstNodeType::IDENTIFIER: { @@ -196,7 +169,7 @@ bool Checker::IsConstantMemberAccess(const ir::Expression *expr) } } -bool Checker::IsStringLike(const ir::Expression *expr) +bool TSChecker::IsStringLike(ir::Expression *expr) { if (expr->IsStringLiteral()) { return true; diff --git a/typescript/types/globalTypesHolder.cpp b/checker/types/globalTypesHolder.cpp similarity index 56% rename from typescript/types/globalTypesHolder.cpp rename to checker/types/globalTypesHolder.cpp index 0b0a4e0db..cab319fff 100644 --- a/typescript/types/globalTypesHolder.cpp +++ b/checker/types/globalTypesHolder.cpp @@ -15,28 +15,41 @@ #include "globalTypesHolder.h" -#include "plugins/ecmascript/es2panda/typescript/types/numberType.h" -#include "plugins/ecmascript/es2panda/typescript/types/anyType.h" -#include "plugins/ecmascript/es2panda/typescript/types/stringType.h" -#include "plugins/ecmascript/es2panda/typescript/types/booleanType.h" -#include "plugins/ecmascript/es2panda/typescript/types/voidType.h" -#include "plugins/ecmascript/es2panda/typescript/types/nullType.h" -#include "plugins/ecmascript/es2panda/typescript/types/undefinedType.h" -#include "plugins/ecmascript/es2panda/typescript/types/unknownType.h" -#include "plugins/ecmascript/es2panda/typescript/types/neverType.h" -#include "plugins/ecmascript/es2panda/typescript/types/nonPrimitiveType.h" -#include "plugins/ecmascript/es2panda/typescript/types/bigintType.h" -#include "plugins/ecmascript/es2panda/typescript/types/booleanLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/bigintLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/numberLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/stringLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/tupleType.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/numberType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/anyType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/stringType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/booleanType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/voidType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/nullType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/undefinedType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unknownType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/neverType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/nonPrimitiveType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/bigintType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/booleanLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/bigintLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/numberLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/stringLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/tupleType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/byteType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/charType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/doubleType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/floatType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/intType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/longType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/shortType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/stsBooleanType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/stsStringType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/stsVoidType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/stsObjectType.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/wildcardType.h" namespace panda::es2panda::checker { GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) { + // TS specific types globalTypes_[static_cast(GlobalTypeId::NUMBER)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::ANY)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::STRING)] = allocator->New(); @@ -65,6 +78,24 @@ GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) globalTypes_[static_cast(GlobalTypeId::EMPTY_OBJECT)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::RESOLVING_RETURN_TYPE)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::ERROR_TYPE)] = allocator->New(); + + // STS specific types + globalTypes_[static_cast(GlobalTypeId::BYTE)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::SHORT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::INT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::LONG)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::FLOAT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::DOUBLE)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::CHAR)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::STS_BOOLEAN)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::STS_VOID)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::STS_OBJECT)] = allocator->New(allocator); + + auto *globalNullType = allocator->New(allocator); + globalNullType->AsSTSObjectType()->AddObjectFlag(STSObjectFlags::NULL_TYPE); + globalTypes_[static_cast(GlobalTypeId::STS_NULL)] = globalNullType; + + globalTypes_[static_cast(GlobalTypeId::STS_WILDCARD)] = allocator->New(); } Type *GlobalTypesHolder::GlobalNumberType() @@ -181,4 +212,69 @@ Type *GlobalTypesHolder::GlobalErrorType() { return globalTypes_.at(static_cast(GlobalTypeId::ERROR_TYPE)); } + +Type *GlobalTypesHolder::GlobalByteType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::BYTE)); +} + +Type *GlobalTypesHolder::GlobalShortType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::SHORT)); +} + +Type *GlobalTypesHolder::GlobalIntType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::INT)); +} + +Type *GlobalTypesHolder::GlobalLongType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::LONG)); +} + +Type *GlobalTypesHolder::GlobalFloatType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::FLOAT)); +} + +Type *GlobalTypesHolder::GlobalDoubleType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::DOUBLE)); +} + +Type *GlobalTypesHolder::GlobalCharType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::CHAR)); +} + +Type *GlobalTypesHolder::GlobalSTSBooleanType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::STS_BOOLEAN)); +} + +Type *GlobalTypesHolder::GlobalSTSStringType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::STS_STRING)); +} + +Type *GlobalTypesHolder::GlobalSTSVoidType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::STS_VOID)); +} + +Type *GlobalTypesHolder::GlobalSTSObjectType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::STS_OBJECT)); +} + +Type *GlobalTypesHolder::GlobalSTSNullType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::STS_NULL)); +} + +Type *GlobalTypesHolder::GLobalWildcardType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::STS_WILDCARD)); +} } // namespace panda::es2panda::checker diff --git a/typescript/types/globalTypesHolder.h b/checker/types/globalTypesHolder.h similarity index 64% rename from typescript/types/globalTypesHolder.h rename to checker/types/globalTypesHolder.h index 6981d5da7..f50dfe4bf 100644 --- a/typescript/types/globalTypesHolder.h +++ b/checker/types/globalTypesHolder.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_GLOBAL_TYPES_HOLDER_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_GLOBAL_TYPES_HOLDER_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { enum class GlobalTypeId { @@ -43,7 +43,20 @@ enum class GlobalTypeId { EMPTY_OBJECT, RESOLVING_RETURN_TYPE, ERROR_TYPE, - COUNT + BYTE, + SHORT, + INT, + LONG, + FLOAT, + DOUBLE, + CHAR, + STS_BOOLEAN, + STS_STRING, + STS_VOID, + STS_OBJECT, + STS_NULL, + STS_WILDCARD, + COUNT, }; class GlobalTypesHolder { @@ -53,6 +66,7 @@ public: NO_COPY_SEMANTIC(GlobalTypesHolder); NO_MOVE_SEMANTIC(GlobalTypesHolder); + // TS specific types Type *GlobalNumberType(); Type *GlobalAnyType(); Type *GlobalStringType(); @@ -77,9 +91,36 @@ public: Type *GlobalResolvingReturnType(); Type *GlobalErrorType(); + // STS specific types + Type *GlobalByteType(); + Type *GlobalShortType(); + Type *GlobalIntType(); + Type *GlobalLongType(); + Type *GlobalFloatType(); + Type *GlobalDoubleType(); + Type *GlobalCharType(); + Type *GlobalSTSBooleanType(); + Type *GlobalSTSStringType(); + Type *GlobalSTSVoidType(); + Type *GlobalSTSObjectType(); + Type *GlobalSTSNullType(); + Type *GLobalWildcardType(); + + using Holder = std::array(GlobalTypeId::COUNT)>; + + Holder &GlobalTypes() + { + return globalTypes_; + } + + const Holder &GlobalTypes() const + { + return globalTypes_; + } + private: - std::array(GlobalTypeId::COUNT)> globalTypes_ {}; + Holder globalTypes_ {}; }; } // namespace panda::es2panda::checker -#endif /* ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H */ +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_GLOBAL_TYPES_HOLDER_H */ diff --git a/typescript/types/signature.cpp b/checker/types/signature.cpp similarity index 81% rename from typescript/types/signature.cpp rename to checker/types/signature.cpp index 80140201d..fc1f220a3 100644 --- a/typescript/types/signature.cpp +++ b/checker/types/signature.cpp @@ -15,18 +15,29 @@ #include "signature.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + namespace panda::es2panda::checker { + +util::StringView Signature::InternalName() const +{ + return internalName_.Empty() ? func_->Scope()->InternalName() : internalName_; +} + Signature *Signature::Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) { - checker::SignatureInfo *copiedInfo = allocator->New(signatureInfo_, allocator); + SignatureInfo *copiedInfo = allocator->New(signatureInfo_, allocator); - for (auto *it : copiedInfo->params) { - it->SetTsType(it->TsType()->Instantiate(allocator, relation, globalTypes)); + for (size_t idx = 0; idx < signatureInfo_->params.size(); idx++) { + copiedInfo->params[idx]->SetTsType( + STSChecker::TryToInstantiate(signatureInfo_->params[idx]->TsType(), allocator, relation, globalTypes)); } - Type *copiedReturnType = returnType_->Instantiate(allocator, relation, globalTypes); + Type *copiedReturnType = STSChecker::TryToInstantiate(returnType_, allocator, relation, globalTypes); - return allocator->New(copiedInfo, copiedReturnType); + return allocator->New(copiedInfo, copiedReturnType, func_); } void Signature::ToString(std::stringstream &ss, const binder::Variable *variable, bool printAsMethod) const @@ -80,7 +91,11 @@ void Signature::Identical(TypeRelation *relation, Signature *other) return; } - relation->IsIdenticalTo(returnType_, other->ReturnType()); + if (relation->NoReturnTypeCheck()) { + relation->Result(true); + } else { + relation->IsIdenticalTo(returnType_, other->ReturnType()); + } if (relation->IsTrue()) { for (uint64_t i = 0; i < signatureInfo_->params.size(); i++) { diff --git a/typescript/types/signature.h b/checker/types/signature.h similarity index 59% rename from typescript/types/signature.h rename to checker/types/signature.h index ea843d456..430195869 100644 --- a/typescript/types/signature.h +++ b/checker/types/signature.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_SIGNATURE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_SIGNATURE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_SIGNATURE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_SIGNATURE_H #include "type.h" @@ -49,12 +49,37 @@ public: // NOLINTEND(misc-non-private-member-variables-in-classes) }; +enum class SignatureFlags { + NO_OPTS = 0, + VIRTUAL = 1 << 0, + ABSTRACT = 1 << 1, + CALL = 1 << 2, + CONSTRUCT = 1 << 3, + PUBLIC = 1 << 4, + PROTECTED = 1 << 5, + PRIVATE = 1 << 6, + STATIC = 1 << 7, + OPEN = 1 << 8, +}; + +DEFINE_BITOPS(SignatureFlags) + class Signature { public: Signature(SignatureInfo *signature_info, Type *returnType) : signatureInfo_(signature_info), returnType_(returnType) { } + Signature(SignatureInfo *signature_info, Type *returnType, util::StringView internalName) + : signatureInfo_(signature_info), returnType_(returnType), internalName_(internalName) + { + } + + Signature(SignatureInfo *signature_info, Type *returnType, ir::ScriptFunction *func) + : signatureInfo_(signature_info), returnType_(returnType), func_(func) + { + } + ~Signature() = default; NO_COPY_SEMANTIC(Signature); NO_MOVE_SEMANTIC(Signature); @@ -94,14 +119,24 @@ public: returnType_ = type; } - void SetNode(const ir::AstNode *node) + void SetOwner(STSObjectType *owner) { - node_ = node; + ownerObj_ = owner; } - const ir::AstNode *Node() const + ir::ScriptFunction *Function() { - return node_; + return func_; + } + + STSObjectType *Owner() + { + return ownerObj_; + } + + const ir::ScriptFunction *Function() const + { + return func_; } const binder::LocalVariable *RestVar() const @@ -109,6 +144,49 @@ public: return signatureInfo_->restVar; } + uint8_t ProtectionFlag() const + { + if (flags_ & SignatureFlags::PRIVATE) { + return 2; + } + + if (flags_ & SignatureFlags::PROTECTED) { + return 1; + } + + return 0; + } + + void AddSignatureFlag(SignatureFlags flag) + { + flags_ |= flag; + } + + void RemoveSignatureFlag(SignatureFlags flag) + { + flags_ &= ~flag; + } + + bool HasSignatureFlag(SignatureFlags flag) const + { + return (flags_ & flag) != 0; + } + + void ToAssemblerType(std::stringstream &ss) const + { + ss << compiler::Signatures::MANGLE_BEGIN; + + for (const auto *param : signatureInfo_->params) { + param->TsType()->ToAssemblerType(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + returnType_->ToAssemblerType(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + util::StringView InternalName() const; + Signature *Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); void ToString(std::stringstream &ss, const binder::Variable *variable, bool printAsMethod = false) const; @@ -118,7 +196,10 @@ public: private: checker::SignatureInfo *signatureInfo_; Type *returnType_; - const ir::AstNode *node_ {}; + ir::ScriptFunction *func_ {}; + SignatureFlags flags_ {SignatureFlags::NO_OPTS}; + util::StringView internalName_ {}; + STSObjectType *ownerObj_ {}; }; } // namespace panda::es2panda::checker diff --git a/checker/types/sts/byteType.cpp b/checker/types/sts/byteType.cpp new file mode 100644 index 000000000..3430b2d8d --- /dev/null +++ b/checker/types/sts/byteType.cpp @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "byteType.h" +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/sts/narrowingConverter.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { +void ByteType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsByteType()) { + relation->Result(true); + } +} + +void ByteType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingConverter(relation->GetChecker()->AsSTSChecker(), relation, this, source); +} + +Type *ByteType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/byteType.h b/checker/types/sts/byteType.h new file mode 100644 index 000000000..707432790 --- /dev/null +++ b/checker/types/sts/byteType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_BYTE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_BYTE_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ByteType : public Type { +public: + using UType = int8_t; + + ByteType() : Type(TypeFlag::BYTE), size_(8) {} + ByteType(UType value) : Type(TypeFlag::BYTE | TypeFlag::CONSTANT), size_(8), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "byte"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_BYTE; + } + +private: + size_t size_; + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/charType.cpp b/checker/types/sts/charType.cpp new file mode 100644 index 000000000..47fe23997 --- /dev/null +++ b/checker/types/sts/charType.cpp @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "charType.h" +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/sts/narrowingConverter.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { +void CharType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsCharType()) { + relation->Result(true); + } +} + +void CharType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingConverter(relation->GetChecker()->AsSTSChecker(), relation, this, source); +} + +Type *CharType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/charType.h b/checker/types/sts/charType.h new file mode 100644 index 000000000..f841fa569 --- /dev/null +++ b/checker/types/sts/charType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_CHAR_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_CHAR_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class CharType : public Type { +public: + using UType = char16_t; + + CharType() : Type(TypeFlag::CHAR), size_(16) {} + CharType(UType value) : Type(TypeFlag::CHAR | TypeFlag::CONSTANT), size_(16), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "char"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_CHAR; + } + +private: + size_t size_; + UType value_ {'\0'}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/doubleType.cpp b/checker/types/sts/doubleType.cpp new file mode 100644 index 000000000..996e12c32 --- /dev/null +++ b/checker/types/sts/doubleType.cpp @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "doubleType.h" +#include "plugins/ecmascript/es2panda/checker/sts/wideningConverter.h" + +namespace panda::es2panda::checker { +void DoubleType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsDoubleType()) { + relation->Result(true); + } +} + +void DoubleType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + WideningConverter(relation->GetChecker()->AsSTSChecker(), relation, this, source); +} + +Type *DoubleType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/doubleType.h b/checker/types/sts/doubleType.h new file mode 100644 index 000000000..3a40c522d --- /dev/null +++ b/checker/types/sts/doubleType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_DOUBLE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_DOUBLE_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class DoubleType : public Type { +public: + using UType = double; + + DoubleType() : Type(TypeFlag::DOUBLE), size_(64) {} + DoubleType(UType value) : Type(TypeFlag::DOUBLE | TypeFlag::CONSTANT), size_(64), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "double"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_DOUBLE; + } + +private: + size_t size_; + UType value_ {0.0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/floatType.cpp b/checker/types/sts/floatType.cpp new file mode 100644 index 000000000..4090af2bb --- /dev/null +++ b/checker/types/sts/floatType.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "floatType.h" + +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/sts/narrowingWideningConverter.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { +void FloatType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsFloatType()) { + relation->Result(true); + } +} + +void FloatType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingWideningConverter(relation->GetChecker()->AsSTSChecker(), relation, this, source); +} + +Type *FloatType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/floatType.h b/checker/types/sts/floatType.h new file mode 100644 index 000000000..a6b3dd774 --- /dev/null +++ b/checker/types/sts/floatType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_FLOAT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_FLOAT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class FloatType : public Type { +public: + using UType = float; + + FloatType() : Type(TypeFlag::FLOAT), size_(32) {} + FloatType(UType value) : Type(TypeFlag::FLOAT | TypeFlag::CONSTANT), size_(32), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "float"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_FLOAT; + } + +private: + size_t size_; + UType value_ {0.0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/intType.cpp b/checker/types/sts/intType.cpp new file mode 100644 index 000000000..c3abf8e49 --- /dev/null +++ b/checker/types/sts/intType.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "intType.h" + +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/sts/narrowingWideningConverter.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { +void IntType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsIntType()) { + relation->Result(true); + } +} + +void IntType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingWideningConverter(relation->GetChecker()->AsSTSChecker(), relation, this, source); +} + +Type *IntType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/intType.h b/checker/types/sts/intType.h new file mode 100644 index 000000000..3ce89cf9c --- /dev/null +++ b/checker/types/sts/intType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_INT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_INT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class IntType : public Type { +public: + using UType = int32_t; + + IntType() : Type(TypeFlag::INT), size_(32) {} + IntType(UType value) : Type(TypeFlag::INT | TypeFlag::CONSTANT), size_(32), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "int"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_INT; + } + +private: + size_t size_; + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/longType.cpp b/checker/types/sts/longType.cpp new file mode 100644 index 000000000..046246395 --- /dev/null +++ b/checker/types/sts/longType.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "longType.h" + +#include "plugins/ecmascript/es2panda/checker/sts/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/sts/narrowingWideningConverter.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { +void LongType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsLongType()) { + relation->Result(true); + } +} + +void LongType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingWideningConverter(relation->GetChecker()->AsSTSChecker(), relation, this, source); +} + +Type *LongType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/longType.h b/checker/types/sts/longType.h new file mode 100644 index 000000000..50a735db9 --- /dev/null +++ b/checker/types/sts/longType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_LONG_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_LONG_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class LongType : public Type { +public: + using UType = int64_t; + + LongType() : Type(TypeFlag::LONG), size_(64) {} + LongType(UType value) : Type(TypeFlag::LONG | TypeFlag::CONSTANT), size_(64), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "long"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_LONG; + } + +private: + size_t size_; + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/shortType.cpp b/checker/types/sts/shortType.cpp new file mode 100644 index 000000000..e3e437573 --- /dev/null +++ b/checker/types/sts/shortType.cpp @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "shortType.h" + +#include "plugins/ecmascript/es2panda/checker/sts/narrowingWideningConverter.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { +void ShortType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsShortType()) { + relation->Result(true); + } +} + +void ShortType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingWideningConverter(relation->GetChecker()->AsSTSChecker(), relation, this, source); +} + +Type *ShortType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/shortType.h b/checker/types/sts/shortType.h new file mode 100644 index 000000000..a4f406827 --- /dev/null +++ b/checker/types/sts/shortType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_SHORT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_SHORT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ShortType : public Type { +public: + using UType = int16_t; + + ShortType() : Type(TypeFlag::SHORT), size_(16) {} + ShortType(UType value) : Type(TypeFlag::SHORT | TypeFlag::CONSTANT), size_(16), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "short"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_SHORT; + } + +private: + size_t size_; + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/stsArrayType.cpp b/checker/types/sts/stsArrayType.cpp new file mode 100644 index 000000000..ec3d476ad --- /dev/null +++ b/checker/types/sts/stsArrayType.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stsArrayType.h" + +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { +void STSArrayType::ToString(std::stringstream &ss) const +{ + element_->ToString(ss); + ss << "[]"; +} + +void STSArrayType::ToAssemblerType(std::stringstream &ss) const +{ + element_->ToAssemblerType(ss); + ss << "[]"; +} + +uint32_t STSArrayType::Rank() const +{ + uint32_t rank = 1; + auto iter = element_; + while (iter->IsSTSArrayType()) { + iter = iter->AsSTSArrayType()->ElementType(); + rank++; + } + + return rank; +} + +void STSArrayType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsSTSArrayType()) { + relation->IsIdenticalTo(element_, other->AsSTSArrayType()->ElementType()); + } +} + +void STSArrayType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (source->IsSTSArrayType()) { + relation->IsAssignableTo(source->AsSTSArrayType()->ElementType(), element_); + } +} + +Type *STSArrayType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + return relation->GetChecker()->AsSTSChecker()->CreateSTSArrayType( + element_->Instantiate(allocator, relation, globalTypes)); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/stsArrayType.h b/checker/types/sts/stsArrayType.h new file mode 100644 index 000000000..7f41f408a --- /dev/null +++ b/checker/types/sts/stsArrayType.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_ARRAY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_ARRAY_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class STSArrayType : public Type { +public: + explicit STSArrayType(Type *elementType) : Type(TypeFlag::STS_ARRAY), element_(elementType) {} + + Type *ElementType() + { + return element_; + } + + const Type *ElementType() const + { + return element_; + } + + void ToString(std::stringstream &ss) const override; + void ToAssemblerType(std::stringstream &ss) const override; + uint32_t Rank() const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + Type *element_; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_ARRAY_TYPE_H */ diff --git a/checker/types/sts/stsBooleanType.cpp b/checker/types/sts/stsBooleanType.cpp new file mode 100644 index 000000000..09a48f8cb --- /dev/null +++ b/checker/types/sts/stsBooleanType.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stsBooleanType.h" + +namespace panda::es2panda::checker { +void STSBooleanType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsSTSBooleanType()) { + relation->Result(true); + } +} + +void STSBooleanType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *STSBooleanType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/stsBooleanType.h b/checker/types/sts/stsBooleanType.h new file mode 100644 index 000000000..0f21ee0ac --- /dev/null +++ b/checker/types/sts/stsBooleanType.h @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_BOOLEAN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_BOOLEAN_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class STSBooleanType : public Type { +public: + using UType = bool; + STSBooleanType() : Type(TypeFlag::STS_BOOLEAN), size_(1) {} + STSBooleanType(UType value) : Type(TypeFlag::STS_BOOLEAN | TypeFlag::CONSTANT), size_(1), value_(value) {} + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + UType GetValue() const + { + return value_; + } + + void ToString(std::stringstream &ss) const override + { + ss << "boolean"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_BOOLEAN; + } + +private: + size_t size_; + UType value_ {false}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/stsFunctionType.cpp b/checker/types/sts/stsFunctionType.cpp new file mode 100644 index 000000000..4cf32fee9 --- /dev/null +++ b/checker/types/sts/stsFunctionType.cpp @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stsFunctionType.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { + +Signature *STSFunctionType::FirstAbstractSignature() +{ + for (auto *it : callSignatures_) { + if (it->HasSignatureFlag(SignatureFlags::ABSTRACT)) { + return it; + } + } + + return nullptr; +} + +void STSFunctionType::ToString(std::stringstream &ss) const +{ + callSignatures_[0]->ToString(ss, nullptr); +} + +void STSFunctionType::Identical(TypeRelation *relation, Type *other) +{ + if (!other->IsSTSFunctionType()) { + return; + } + + callSignatures_[0]->Identical(relation, other->AsSTSFunctionType()->CallSignatures()[0]); +} + +void STSFunctionType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + callSignatures_[0]->AssignmentTarget(relation, source->AsSTSFunctionType()->CallSignatures()[0]); +} + +Type *STSFunctionType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + auto *copiedType = relation->GetChecker()->AsSTSChecker()->CreateSTSFunctionType(name_); + + for (auto *it : callSignatures_) { + copiedType->AddCallSignature(it->Copy(allocator, relation, globalTypes)); + } + + return copiedType; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/stsFunctionType.h b/checker/types/sts/stsFunctionType.h new file mode 100644 index 000000000..7abf101af --- /dev/null +++ b/checker/types/sts/stsFunctionType.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_FUNCTION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_FUNCTION_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +namespace panda::es2panda::checker { + +class STSFunctionType : public Type { +public: + explicit STSFunctionType(util::StringView name, Signature *signature, ArenaAllocator *allocator) + : Type(TypeFlag::FUNCTION), callSignatures_(allocator->Adapter()), name_(name) + { + callSignatures_.push_back(signature); + } + + STSFunctionType(util::StringView name, ArenaAllocator *allocator) + : Type(TypeFlag::FUNCTION), callSignatures_(allocator->Adapter()), name_(name) + { + } + + ArenaVector &CallSignatures() + { + return callSignatures_; + } + + const ArenaVector &CallSignatures() const + { + return callSignatures_; + } + + const util::StringView Name() const + { + return name_; + } + + void AddCallSignature(Signature *signature) + { + callSignatures_.push_back(signature); + } + + Signature *FindSignature(const ir::ScriptFunction *func) const + { + for (auto *it : callSignatures_) { + if (it->Function() == func) { + return it; + } + } + + return nullptr; + } + + Signature *FirstAbstractSignature(); + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + ArenaVector callSignatures_; + util::StringView name_; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_FUNCTION_TYPE_H */ diff --git a/checker/types/sts/stsObjectType.cpp b/checker/types/sts/stsObjectType.cpp new file mode 100644 index 000000000..88398129e --- /dev/null +++ b/checker/types/sts/stsObjectType.cpp @@ -0,0 +1,248 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stsObjectType.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" + +namespace panda::es2panda::checker { + +void STSObjectType::Iterate(const PropertyTraverser &cb) const +{ + for (const auto &[_, prop] : properties_) { + cb(prop); + } + + if (superType_) { + superType_->Iterate(cb); + } + + for (const auto *interface : interfaces_) { + interface->Iterate(cb); + } +} + +binder::LocalVariable *STSObjectType::GetProperty(const util::StringView &name, PropertySearchFlags flags) const +{ + const auto it = properties_.find(name); + if (it != properties_.end()) { + if (!(flags & (PropertySearchFlags::IGNORE_STATIC | PropertySearchFlags::IGNORE_INSTANCE_FIELD))) { + return it->second; + } + + if ((flags & PropertySearchFlags::IGNORE_STATIC) && !it->second->HasFlag(binder::VariableFlags::STATIC)) { + return it->second; + } + + if ((flags & PropertySearchFlags::IGNORE_INSTANCE_FIELD) && + it->second->HasFlag(binder::VariableFlags::STATIC)) { + return it->second; + } + } + + if (superType_ && (flags & PropertySearchFlags::SEARCH_IN_BASE)) { + auto *prop = superType_->GetProperty(name, flags); + + if (prop) { + return prop; + } + } + + if (flags & PropertySearchFlags::SEARCH_IN_INTERFACES) { + for (auto *interface : interfaces_) { + auto *prop = interface->GetProperty(name, flags); + + if (prop) { + return prop; + } + } + } + + return nullptr; +} + +std::vector STSObjectType::ForeignProperties() const +{ + std::vector foreignProps; + std::unordered_set ownProps; + ownProps.reserve(properties_.size()); + + for (const auto &[propName, _] : properties_) { + ownProps.insert(propName); + } + + auto allProps = CollectAllProperties(); + for (const auto &[name, var] : allProps) { + if (ownProps.find(name) == ownProps.end()) { + foreignProps.push_back(var); + } + } + + return foreignProps; +} + +std::unordered_map STSObjectType::CollectAllProperties() const +{ + std::unordered_map propMap; + propMap.reserve(properties_.size()); + Iterate([&propMap](const binder::LocalVariable *var) { propMap.insert({var->Name(), var}); }); + + return propMap; +} + +void STSObjectType::ToString(std::stringstream &ss) const +{ + ss << name_; +} + +void STSObjectType::Identical(TypeRelation *relation, Type *other) +{ + if (!other->IsSTSObjectType() || !other->AsSTSObjectType()->HasObjectFlag(STSObjectFlags::CLASS)) { + return; + } + + if (variable_ != other->Variable()) { + return; + } + + STSObjectType *otherObj = other->AsSTSObjectType(); + if (typeArguments_.empty() != otherObj->TypeArguments().empty()) { + return; + } + + if (!typeArguments_.empty()) { + ASSERT(typeArguments_.size() == otherObj->TypeArguments().size()); + for (size_t idx = 0; idx < typeArguments_.size(); idx++) { + typeArguments_[idx]->Identical(relation, otherObj->TypeArguments()[idx]); + if (!relation->IsTrue()) { + return; + } + } + } + + relation->Result(true); +} + +bool STSObjectType::AssignmentSource([[maybe_unused]] TypeRelation *relation, Type *target) +{ + return target->IsSTSNullType(); +} + +void STSObjectType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (source->IsSTSNullType()) { + relation->Result(true); + return; + } + IsSubtype(relation, source); +} + +void STSObjectType::IsSubtype(TypeRelation *relation, Type *source) +{ + if (!source->IsSTSObjectType() || !source->AsSTSObjectType()->HasObjectFlag(STSObjectFlags::CLASS)) { + return; + } + + STSObjectType *sourceObj = source->AsSTSObjectType(); + Type *sup = sourceObj->AsSuper(relation->GetChecker(), variable_); + if (!sup) { + return; + } + + relation->Result(true); +} + +Type *STSObjectType::AsSuper(Checker *checker, binder::Variable *sourceVar) +{ + if (!sourceVar) { + return nullptr; + } + + if (variable_ == sourceVar) { + return this; + } + + if (!checker->TypeStack().insert(sourceVar).second) { + return nullptr; + } + + Type *superType = checker->AsSTSChecker()->GetSuperType(this); + + if (!superType) { + return this; + } + + if (!superType->IsSTSObjectType()) { + checker->TypeStack().erase(sourceVar); + return nullptr; + } + + STSObjectType *superObj = superType->AsSTSObjectType(); + + if (superObj->HasObjectFlag(STSObjectFlags::CLASS)) { + Type *res = superObj->AsSuper(checker, sourceVar); + if (res) { + checker->TypeStack().erase(sourceVar); + return res; + } + } + + if (sourceVar->Declaration()->Node()->IsTSInterfaceDeclaration()) { + ArenaVector interfaces = checker->AsSTSChecker()->GetInterfaces(this); + for (auto *it : interfaces) { + Type *res = it->AsSuper(checker, sourceVar); + if (res) { + checker->TypeStack().erase(sourceVar); + return res; + } + } + } + + checker->TypeStack().erase(sourceVar); + return nullptr; +} + +Type *STSObjectType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + auto *checker = relation->GetChecker()->AsSTSChecker(); + auto *copiedType = checker->CreateNewSTSObjectType(name_, declNode_, flags_); + copiedType->RemoveObjectFlag(STSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS | + STSObjectFlags::UNCOMPLETE_INSTANTIATION); + + copiedType->SetVariable(variable_); + copiedType->SetSuperType(superType_); + + for (auto *it : interfaces_) { + copiedType->AddInterface(it); + } + + for (auto &[_, it] : properties_) { + auto *copiedProp = it->Copy(allocator, it->Declaration()); + auto *copiedPropType = STSChecker::TryToInstantiate(it->TsType(), allocator, relation, globalTypes); + copiedPropType->SetVariable(copiedProp); + copiedProp->SetTsType(copiedPropType); + copiedType->AddProperty(copiedProp); + } + + for (auto *it : constructSignatures_) { + copiedType->AddConstructSignature(it->Copy(allocator, relation, globalTypes)); + } + + return copiedType; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/stsObjectType.h b/checker/types/sts/stsObjectType.h new file mode 100644 index 000000000..0c0889ee8 --- /dev/null +++ b/checker/types/sts/stsObjectType.h @@ -0,0 +1,313 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_OBJECT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_OBJECT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +namespace panda::es2panda::checker { + +enum class STSObjectFlags { + NO_OPTS = 0, + CLASS = 1 << 0, + INTERFACE = 1 << 1, + INSTANCE = 1 << 2, + ABSTRACT = 1 << 3, + GLOBAL = 1 << 4, + ENUM = 1 << 5, + RESOLVED_MEMBERS = 1 << 6, + RESOLVED_INTERFACES = 1 << 7, + RESOLVED_SUPER = 1 << 8, + RESOLVED_TYPE_PARAMS = 1 << 9, + CHECKED_COMPATIBLE_ABSTRACTS = 1 << 10, + NULL_TYPE = 1 << 11, + STRING = 1 << 12, + UNCOMPLETE_INSTANTIATION = 1 << 13, + + BUILTIN_STRING = 1 << 23, + BUILTIN_BOOLEAN = 1 << 24, + BUILTIN_BYTE = 1 << 25, + BUILTIN_CHAR = 1 << 26, + BUILTIN_SHORT = 1 << 27, + BUILTIN_INT = 1 << 28, + BUILTIN_LONG = 1 << 29, + BUILTIN_FLOAT = 1 << 30, + BUILTIN_DOUBLE = 1 << 31, + + BUILTIN_TYPE = BUILTIN_STRING | BUILTIN_BOOLEAN | BUILTIN_BYTE | BUILTIN_CHAR | BUILTIN_SHORT | BUILTIN_INT | + BUILTIN_LONG | BUILTIN_FLOAT | BUILTIN_DOUBLE, + GLOBAL_CLASS = CLASS | GLOBAL, +}; + +DEFINE_BITOPS(STSObjectFlags) + +enum class PropertySearchFlags { + NO_OPTS = 0, + SEARCH_IN_BASE = 1 << 0, + SEARCH_IN_INTERFACES = 1 << 1, + IGNORE_STATIC = 1 << 2, + IGNORE_INSTANCE_FIELD = 1 << 3, + + SEARCH_ALL = SEARCH_IN_BASE | SEARCH_IN_INTERFACES, +}; + +DEFINE_BITOPS(PropertySearchFlags) + +class STSObjectType : public Type { +public: + using PropertyMap = ArenaUnorderedMap; + using InstantiationMap = ArenaUnorderedMap; + using PropertyTraverser = std::function; + + explicit STSObjectType(ArenaAllocator *allocator) : STSObjectType(allocator, STSObjectFlags::NO_OPTS) {} + + explicit STSObjectType(ArenaAllocator *allocator, STSObjectFlags flags) + : STSObjectType(allocator, "", "", nullptr, flags) + { + } + + explicit STSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView assemblerName, + ir::AstNode *declNode, STSObjectFlags flags) + : Type(TypeFlag::STS_OBJECT), + name_(name), + assemblerName_(assemblerName), + declNode_(declNode), + properties_(allocator->Adapter()), + constructSignatures_(allocator->Adapter()), + interfaces_(allocator->Adapter()), + flags_(flags), + instantiationMap_(allocator->Adapter()), + typeArguments_(allocator->Adapter()) + { + } + + void AddProperty(binder::LocalVariable *prop) + { + properties_.insert({prop->Name(), prop}); + } + + void AddConstructSignature(Signature *signature) + { + constructSignatures_.push_back(signature); + } + + void AddConstructSignature(const ArenaVector &signatures) + { + constructSignatures_.insert(constructSignatures_.end(), signatures.cbegin(), signatures.cend()); + } + + void AddInterface(STSObjectType *interface) + { + interfaces_.push_back(interface); + } + + void SetSuperType(STSObjectType *super) + { + superType_ = super; + } + + void SetTypeArguments(ArenaVector &&typeArgs) + { + typeArguments_ = std::move(typeArgs); + } + + void SetEnclosingType(STSObjectType *enclosingType) + { + enclosingType_ = enclosingType; + } + + binder::LocalVariable *GetProperty(const util::StringView &name, PropertySearchFlags flags) const; + + const ArenaUnorderedMap &Properties() const + { + return properties_; + } + + ArenaUnorderedMap &Properties() + { + return properties_; + } + + const ArenaVector &TypeArguments() const + { + return typeArguments_; + } + + ArenaVector &TypeArguments() + { + return typeArguments_; + } + + const ArenaVector &ConstructSignatures() const + { + return constructSignatures_; + } + + ArenaVector &ConstructSignatures() + { + return constructSignatures_; + } + + const ArenaVector &Interfaces() const + { + return interfaces_; + } + + ArenaVector &Interfaces() + { + return interfaces_; + } + + ir::AstNode *GetDeclNode() const + { + return declNode_; + } + + const STSObjectType *SuperType() const + { + return superType_; + } + + STSObjectType *SuperType() + { + return superType_; + } + + const STSObjectType *EnclosingType() const + { + return enclosingType_; + } + + STSObjectType *EnclosingType() + { + return enclosingType_; + } + + STSObjectType *OutermostClass() + { + auto *iter = enclosingType_; + + while (iter && iter->EnclosingType()) { + iter = iter->EnclosingType(); + } + + return iter; + } + + bool IsPropertyInherited(binder::Variable *var) + { + if (var->HasFlag(binder::VariableFlags::PRIVATE)) { + return GetProperty(var->Name(), PropertySearchFlags::NO_OPTS) == var; + } + + return true; + } + + bool IsSignatureInherited(Signature *signature) + { + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + return signature->Owner() == this; + } + + return true; + } + + const util::StringView &Name() const + { + return name_; + } + + const util::StringView &AssemblerName() const + { + return assemblerName_; + } + + STSObjectFlags ObjectFlags() const + { + return flags_; + } + + void AddObjectFlag(STSObjectFlags flag) + { + flags_ |= flag; + } + + void RemoveObjectFlag(STSObjectFlags flag) + { + flags_ &= ~flag; + } + + bool HasObjectFlag(STSObjectFlags flag) const + { + return (flags_ & flag) != 0; + } + + STSObjectFlags BuiltInKind() + { + return static_cast(flags_ & STSObjectFlags::BUILTIN_TYPE); + } + + STSObjectType *GetInstantiatedType(util::StringView hash) + { + auto found = instantiationMap_.find(hash); + + if (found != instantiationMap_.end()) { + return found->second; + } + + return nullptr; + } + + InstantiationMap &GetInstantiationMap() + { + return instantiationMap_; + } + + std::vector ForeignProperties() const; + + void Iterate(const PropertyTraverser &cb) const; + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + bool AssignmentSource(TypeRelation *relation, Type *target) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + void IsSubtype(TypeRelation *relation, Type *source) override; + Type *AsSuper(Checker *checker, binder::Variable *sourceVar) override; + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << assemblerName_; + } + +private: + std::unordered_map CollectAllProperties() const; + + util::StringView name_; + util::StringView assemblerName_; + ir::AstNode *declNode_; + PropertyMap properties_; + ArenaVector constructSignatures_; + ArenaVector interfaces_; + STSObjectFlags flags_; + InstantiationMap instantiationMap_; + ArenaVector typeArguments_; + STSObjectType *superType_ {}; + STSObjectType *enclosingType_ {}; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_FUNCTION_TYPE_H */ diff --git a/checker/types/sts/stsStringType.cpp b/checker/types/sts/stsStringType.cpp new file mode 100644 index 000000000..ddd145529 --- /dev/null +++ b/checker/types/sts/stsStringType.cpp @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stsStringType.h" + +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" + +namespace panda::es2panda::checker { +void STSStringType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsSTSStringType()) { + relation->Result(true); + } +} + +void STSStringType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *STSStringType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/stsStringType.h b/checker/types/sts/stsStringType.h new file mode 100644 index 000000000..cb6531819 --- /dev/null +++ b/checker/types/sts/stsStringType.h @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_STRING_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_STRING_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/sts/stsObjectType.h" + +namespace panda::es2panda::checker { +class STSStringType : public STSObjectType { +public: + explicit STSStringType(ArenaAllocator *allocator, [[maybe_unused]] STSObjectType *super) + : STSObjectType(allocator, STSObjectFlags::CLASS | STSObjectFlags::STRING | STSObjectFlags::RESOLVED_SUPER) + { + SetSuperType(super); + } + + explicit STSStringType(ArenaAllocator *allocator, STSObjectType *super, util::StringView value) + : STSObjectType(allocator, STSObjectFlags::CLASS | STSObjectFlags::STRING | STSObjectFlags::RESOLVED_SUPER), + value_(value) + { + SetSuperType(super); + AddTypeFlag(TypeFlag::CONSTANT); + variable_ = super->Variable(); + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "string"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::BUILTIN_STRING; + } + + util::StringView GetValue() const + { + return value_; + } + +private: + util::StringView value_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/stsTypeParameter.cpp b/checker/types/sts/stsTypeParameter.cpp new file mode 100644 index 000000000..a42067db9 --- /dev/null +++ b/checker/types/sts/stsTypeParameter.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stsTypeParameter.h" + +namespace panda::es2panda::checker { +void STSTypeParameter::ToString([[maybe_unused]] std::stringstream &ss) const +{ + UNREACHABLE(); +} + +void STSTypeParameter::Identical([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *other) +{ + UNREACHABLE(); +} + +void STSTypeParameter::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) +{ + UNREACHABLE(); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/stsTypeParameter.h b/checker/types/sts/stsTypeParameter.h new file mode 100644 index 000000000..19b9f1c40 --- /dev/null +++ b/checker/types/sts/stsTypeParameter.h @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_TYPE_PARAMETER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_TYPE_PARAMETER_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class STSTypeParameter : public Type { +public: + explicit STSTypeParameter() : Type(TypeFlag::STS_TYPE_PARAMETER) {} + explicit STSTypeParameter(Type *assemblerType) : Type(TypeFlag::STS_TYPE_PARAMETER), assemblerType_(assemblerType) {} + + void SetType(Type *type) + { + type_ = type; + } + + Type *GetType() + { + return type_; + } + + Type *GetAssemblerType() + { + return assemblerType_; + } + + Type **GetTypeRef() + { + return &type_; + } + + Type **GetAssemblerTypeRef() + { + return &assemblerType_; + } + + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + +private: + Type *type_ {}; + Type *assemblerType_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/sts/stsTypeReference.cpp b/checker/types/sts/stsTypeReference.cpp new file mode 100644 index 000000000..9e6b99569 --- /dev/null +++ b/checker/types/sts/stsTypeReference.cpp @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stsTypeReference.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" + +namespace panda::es2panda::checker { + +util::StringView STSTypeReference::ReferencedName() const +{ + return varRef_->Name(); +} + +void STSTypeReference::ToString(std::stringstream &ss) const +{ + ss << ReferencedName(); +} + +void STSTypeReference::ToAssemblerType(std::stringstream &ss) const +{ + ASSERT(*assemblerRef_); + (*assemblerRef_)->ToAssemblerType(ss); +} + +void STSTypeReference::Identical(TypeRelation *relation, Type *other) +{ + if (*ref_) { + (*ref_)->Identical(relation, other); + return; + } + + if (!other->IsSTSTypeReference()) { + return; + } + + relation->Result(varRef_ == other->AsSTSTypeReference()->VarRef()); +} + +void STSTypeReference::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (*ref_) { + (*ref_)->AssignmentTarget(relation, source); + } +} + +bool STSTypeReference::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (!(*ref_)) { + return false; + } + + if (!target->IsSTSTypeReference()) { + return true; + } + + if (!relation->IsAssignableTo(this, target)) { + return true; + } + + relation->Result(true); + return false; +} + +Type *STSTypeReference::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + if (*ref_) { + return (*ref_)->Instantiate(allocator, relation, globalTypes); + } + + return relation->GetChecker()->AsSTSChecker()->CreateTypeReference(ref_, assemblerRef_, varRef_); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/stsTypeReference.h b/checker/types/sts/stsTypeReference.h new file mode 100644 index 000000000..2b66de4b2 --- /dev/null +++ b/checker/types/sts/stsTypeReference.h @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_TYPE_REFERENCE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_TYPE_REFERENCE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::binder { +class LocalVariable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +class STSTypeReference : public Type { +public: + explicit STSTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *varRef) + : Type(TypeFlag::STS_TYPE_REFERENCE), ref_(ref), assemblerRef_(assemblerRef), varRef_(varRef) + { + } + + Type *Ref() + { + return *ref_; + } + + const Type *Ref() const + { + return *ref_; + } + + binder::LocalVariable *VarRef() + { + return varRef_; + } + + const binder::LocalVariable *VarRef() const + { + return varRef_; + } + + util::StringView ReferencedName() const; + + void ToString(std::stringstream &ss) const override; + void ToAssemblerType(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + Type **ref_; + Type **assemblerRef_; + binder::LocalVariable *varRef_ {}; +}; +} // namespace panda::es2panda::checker + +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H */ diff --git a/checker/types/sts/stsVoidType.cpp b/checker/types/sts/stsVoidType.cpp new file mode 100644 index 000000000..6afff98cd --- /dev/null +++ b/checker/types/sts/stsVoidType.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stsVoidType.h" + +namespace panda::es2panda::checker { +void STSVoidType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsSTSVoidType()) { + relation->Result(true); + } +} + +void STSVoidType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *STSVoidType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/lexer/templates/keywordsMap.h.erb b/checker/types/sts/stsVoidType.h similarity index 42% rename from lexer/templates/keywordsMap.h.erb rename to checker/types/sts/stsVoidType.h index 46d4cc8bb..86eb786a8 100644 --- a/lexer/templates/keywordsMap.h.erb +++ b/checker/types/sts/stsVoidType.h @@ -13,37 +13,32 @@ * limitations under the License. */ -// Autogenerated file -- DO NOT EDIT! +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_VOID_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_VOID_TYPE_H -#include "plugins/ecmascript/es2panda/lexer/keywordString.h" -#include "utils/span.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" -namespace panda::es2panda::lexer { -class KeywordsMap { +namespace panda::es2panda::checker { +class STSVoidType : public Type { public: - KeywordsMap() = delete; - - static Span Map(char32_t cp) { - switch(cp) { -% keywords.each do |group| - case LEX_CHAR_LOWERCASE_<%= group.keys[0][0].upcase %>: { - return Span(KEYWORDS_<%= group.keys[0][0].upcase %>); - } -% end - default: { - return Span(); - } - } + STSVoidType() : Type(TypeFlag::STS_VOID) {} + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "void"; } -% keywords.each do |group| + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_VOID; + } - static constexpr std::array> KEYWORDS_<%= group.keys[0][0].upcase %> = {{ -% group.each do |key, kw| - {"<%= key%>", <%= kw[0] %>, <%= kw[1] %>}, -% end - }}; -% end +private: }; +} // namespace panda::es2panda::checker -} // namespace panda::es2panda::lexer +#endif diff --git a/checker/types/sts/types.h b/checker/types/sts/types.h new file mode 100644 index 000000000..9bf30be8e --- /dev/null +++ b/checker/types/sts/types.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_H + +#include "byteType.h" +#include "charType.h" +#include "doubleType.h" +#include "floatType.h" +#include "intType.h" +#include "longType.h" +#include "shortType.h" +#include "stsBooleanType.h" +#include "stsFunctionType.h" +#include "charType.h" +#include "stsVoidType.h" +#include "stsStringType.h" +#include "stsObjectType.h" +#include "stsArrayType.h" +#include "wildcardType.h" +#include "stsTypeReference.h" +#include "stsTypeParameter.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +#endif /* TYPES_H */ diff --git a/checker/types/sts/wildcardType.cpp b/checker/types/sts/wildcardType.cpp new file mode 100644 index 000000000..ca8c974c8 --- /dev/null +++ b/checker/types/sts/wildcardType.cpp @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wildcardType.h" + +namespace panda::es2panda::checker { +void WildcardType::ToString(std::stringstream &ss) const +{ + ss << "wildcard"; +} + +void WildcardType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsWildcardType()) { + relation->Result(true); + } +} + +void WildcardType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *WildcardType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/sts/wildcardType.h b/checker/types/sts/wildcardType.h new file mode 100644 index 000000000..295d5bcaa --- /dev/null +++ b/checker/types/sts/wildcardType.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_STS_WILDCARD_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_STS_WILDCARD_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class WildcardType : public Type { +public: + WildcardType() : Type(TypeFlag::WILDCARD) {} + + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << "wildcard"; + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/typescript/types/anyType.cpp b/checker/types/ts/anyType.cpp similarity index 100% rename from typescript/types/anyType.cpp rename to checker/types/ts/anyType.cpp diff --git a/typescript/types/anyType.h b/checker/types/ts/anyType.h similarity index 87% rename from typescript/types/anyType.h rename to checker/types/ts/anyType.h index 8105bebf3..76c38e62e 100644 --- a/typescript/types/anyType.h +++ b/checker/types/ts/anyType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ANY_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ANY_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ANY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ANY_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class AnyType : public Type { @@ -32,4 +32,4 @@ public: }; } // namespace panda::es2panda::checker -#endif /* TYPESCRIPT_TYPES_ANY_TYPE_H */ +#endif diff --git a/typescript/types/arrayType.cpp b/checker/types/ts/arrayType.cpp similarity index 96% rename from typescript/types/arrayType.cpp rename to checker/types/ts/arrayType.cpp index 78d105513..90deba9dc 100644 --- a/typescript/types/arrayType.cpp +++ b/checker/types/ts/arrayType.cpp @@ -16,7 +16,7 @@ #include "arrayType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" namespace panda::es2panda::checker { void ArrayType::ToString(std::stringstream &ss) const diff --git a/typescript/types/arrayType.h b/checker/types/ts/arrayType.h similarity index 89% rename from typescript/types/arrayType.h rename to checker/types/ts/arrayType.h index 4e28e70f8..27e61711a 100644 --- a/typescript/types/arrayType.h +++ b/checker/types/ts/arrayType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ARRAY_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ARRAY_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ARRAY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ARRAY_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class ArrayType : public Type { diff --git a/typescript/types/bigintLiteralType.cpp b/checker/types/ts/bigintLiteralType.cpp similarity index 100% rename from typescript/types/bigintLiteralType.cpp rename to checker/types/ts/bigintLiteralType.cpp diff --git a/typescript/types/bigintLiteralType.h b/checker/types/ts/bigintLiteralType.h similarity index 89% rename from typescript/types/bigintLiteralType.h rename to checker/types/ts/bigintLiteralType.h index aef7b39c9..f0fd4b1f5 100644 --- a/typescript/types/bigintLiteralType.h +++ b/checker/types/ts/bigintLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BigintLiteralType : public Type { diff --git a/typescript/types/bigintType.cpp b/checker/types/ts/bigintType.cpp similarity index 100% rename from typescript/types/bigintType.cpp rename to checker/types/ts/bigintType.cpp diff --git a/typescript/types/bigintType.h b/checker/types/ts/bigintType.h similarity index 87% rename from typescript/types/bigintType.h rename to checker/types/ts/bigintType.h index d3022f3cc..07636b22d 100644 --- a/typescript/types/bigintType.h +++ b/checker/types/ts/bigintType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BigintType : public Type { diff --git a/typescript/types/booleanLiteralType.cpp b/checker/types/ts/booleanLiteralType.cpp similarity index 100% rename from typescript/types/booleanLiteralType.cpp rename to checker/types/ts/booleanLiteralType.cpp diff --git a/typescript/types/booleanLiteralType.h b/checker/types/ts/booleanLiteralType.h similarity index 88% rename from typescript/types/booleanLiteralType.h rename to checker/types/ts/booleanLiteralType.h index 8f7b46c3b..f10bfc2dd 100644 --- a/typescript/types/booleanLiteralType.h +++ b/checker/types/ts/booleanLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BooleanLiteralType : public Type { diff --git a/typescript/types/booleanType.cpp b/checker/types/ts/booleanType.cpp similarity index 100% rename from typescript/types/booleanType.cpp rename to checker/types/ts/booleanType.cpp diff --git a/typescript/types/booleanType.h b/checker/types/ts/booleanType.h similarity index 87% rename from typescript/types/booleanType.h rename to checker/types/ts/booleanType.h index 463b5c596..e16b95c68 100644 --- a/typescript/types/booleanType.h +++ b/checker/types/ts/booleanType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BooleanType : public Type { diff --git a/typescript/types/constructorType.cpp b/checker/types/ts/constructorType.cpp similarity index 95% rename from typescript/types/constructorType.cpp rename to checker/types/ts/constructorType.cpp index 15edc26fd..3af66bc5a 100644 --- a/typescript/types/constructorType.cpp +++ b/checker/types/ts/constructorType.cpp @@ -15,7 +15,7 @@ #include "constructorType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { void ConstructorType::ToString(std::stringstream &ss) const diff --git a/typescript/types/constructorType.h b/checker/types/ts/constructorType.h similarity index 90% rename from typescript/types/constructorType.h rename to checker/types/ts/constructorType.h index 0776b2f19..4c930cee4 100644 --- a/typescript/types/constructorType.h +++ b/checker/types/ts/constructorType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_CONSTRUCTOR_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_CONSTRUCTOR_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_CONSTRUCTOR_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_CONSTRUCTOR_TYPE_H #include "objectType.h" diff --git a/typescript/types/elementFlags.h b/checker/types/ts/elementFlags.h similarity index 90% rename from typescript/types/elementFlags.h rename to checker/types/ts/elementFlags.h index dba255767..2ced2a122 100644 --- a/typescript/types/elementFlags.h +++ b/checker/types/ts/elementFlags.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ELEMENT_FLAGS_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ELEMENT_FLAGS_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ELEMENT_FLAGS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ELEMENT_FLAGS_H #include "plugins/ecmascript/es2panda/util/enumbitops.h" diff --git a/typescript/types/enumLiteralType.cpp b/checker/types/ts/enumLiteralType.cpp similarity index 96% rename from typescript/types/enumLiteralType.cpp rename to checker/types/ts/enumLiteralType.cpp index 79984a9e3..f6b7bc3ce 100644 --- a/typescript/types/enumLiteralType.cpp +++ b/checker/types/ts/enumLiteralType.cpp @@ -16,7 +16,7 @@ #include "enumLiteralType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void EnumLiteralType::ToString(std::stringstream &ss) const diff --git a/typescript/types/enumLiteralType.h b/checker/types/ts/enumLiteralType.h similarity index 90% rename from typescript/types/enumLiteralType.h rename to checker/types/ts/enumLiteralType.h index 1b601a2c4..a0ddeb725 100644 --- a/typescript/types/enumLiteralType.h +++ b/checker/types/ts/enumLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::binder { class Scope; diff --git a/typescript/types/enumType.cpp b/checker/types/ts/enumType.cpp similarity index 100% rename from typescript/types/enumType.cpp rename to checker/types/ts/enumType.cpp diff --git a/typescript/types/enumType.h b/checker/types/ts/enumType.h similarity index 90% rename from typescript/types/enumType.h rename to checker/types/ts/enumType.h index 2c8cf92f8..1a06fb731 100644 --- a/typescript/types/enumType.h +++ b/checker/types/ts/enumType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::binder { class EnumVariable; diff --git a/typescript/types/functionType.cpp b/checker/types/ts/functionType.cpp similarity index 96% rename from typescript/types/functionType.cpp rename to checker/types/ts/functionType.cpp index 274dceefc..d3748baf3 100644 --- a/typescript/types/functionType.cpp +++ b/checker/types/ts/functionType.cpp @@ -15,7 +15,7 @@ #include "functionType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { void FunctionType::ToString(std::stringstream &ss) const diff --git a/typescript/types/functionType.h b/checker/types/ts/functionType.h similarity index 90% rename from typescript/types/functionType.h rename to checker/types/ts/functionType.h index 4527c6b99..f1b465a54 100644 --- a/typescript/types/functionType.h +++ b/checker/types/ts/functionType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_FUNCTION_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_FUNCTION_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_FUNCTION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_FUNCTION_TYPE_H #include #include "objectType.h" diff --git a/typescript/types/indexInfo.cpp b/checker/types/ts/indexInfo.cpp similarity index 100% rename from typescript/types/indexInfo.cpp rename to checker/types/ts/indexInfo.cpp diff --git a/typescript/types/indexInfo.h b/checker/types/ts/indexInfo.h similarity index 92% rename from typescript/types/indexInfo.h rename to checker/types/ts/indexInfo.h index 111079a3b..79e252ebc 100644 --- a/typescript/types/indexInfo.h +++ b/checker/types/ts/indexInfo.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INDEX_INFO_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INDEX_INFO_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_INDEX_INFO_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_INDEX_INFO_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class IndexInfo { diff --git a/typescript/types/interfaceType.cpp b/checker/types/ts/interfaceType.cpp similarity index 98% rename from typescript/types/interfaceType.cpp rename to checker/types/ts/interfaceType.cpp index f9f48b683..2d093f1f7 100644 --- a/typescript/types/interfaceType.cpp +++ b/checker/types/ts/interfaceType.cpp @@ -16,8 +16,8 @@ #include "interfaceType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeParameter.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/typeParameter.h" #include #include diff --git a/typescript/types/interfaceType.h b/checker/types/ts/interfaceType.h similarity index 97% rename from typescript/types/interfaceType.h rename to checker/types/ts/interfaceType.h index 1788e719a..d929906a0 100644 --- a/typescript/types/interfaceType.h +++ b/checker/types/ts/interfaceType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INTERFACE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INTERFACE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_INTERFACE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_INTERFACE_TYPE_H #include "objectType.h" diff --git a/typescript/types/neverType.cpp b/checker/types/ts/neverType.cpp similarity index 100% rename from typescript/types/neverType.cpp rename to checker/types/ts/neverType.cpp diff --git a/typescript/types/neverType.h b/checker/types/ts/neverType.h similarity index 87% rename from typescript/types/neverType.h rename to checker/types/ts/neverType.h index d103dc77c..606e255f4 100644 --- a/typescript/types/neverType.h +++ b/checker/types/ts/neverType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NEVER_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NEVER_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NEVER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NEVER_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NeverType : public Type { diff --git a/typescript/types/nonPrimitiveType.cpp b/checker/types/ts/nonPrimitiveType.cpp similarity index 100% rename from typescript/types/nonPrimitiveType.cpp rename to checker/types/ts/nonPrimitiveType.cpp diff --git a/typescript/types/nonPrimitiveType.h b/checker/types/ts/nonPrimitiveType.h similarity index 86% rename from typescript/types/nonPrimitiveType.h rename to checker/types/ts/nonPrimitiveType.h index ea646d161..380aaa316 100644 --- a/typescript/types/nonPrimitiveType.h +++ b/checker/types/ts/nonPrimitiveType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NON_PRIMITIVE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NON_PRIMITIVE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NON_PRIMITIVE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NON_PRIMITIVE_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NonPrimitiveType : public Type { diff --git a/typescript/types/nullType.cpp b/checker/types/ts/nullType.cpp similarity index 100% rename from typescript/types/nullType.cpp rename to checker/types/ts/nullType.cpp diff --git a/typescript/types/nullType.h b/checker/types/ts/nullType.h similarity index 88% rename from typescript/types/nullType.h rename to checker/types/ts/nullType.h index 45f37fc48..16b4a614c 100644 --- a/typescript/types/nullType.h +++ b/checker/types/ts/nullType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NULL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NULL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NULL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NULL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NullType : public Type { diff --git a/typescript/types/numberLiteralType.cpp b/checker/types/ts/numberLiteralType.cpp similarity index 96% rename from typescript/types/numberLiteralType.cpp rename to checker/types/ts/numberLiteralType.cpp index f72e6f6cd..c94f81681 100644 --- a/typescript/types/numberLiteralType.cpp +++ b/checker/types/ts/numberLiteralType.cpp @@ -17,7 +17,7 @@ #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void NumberLiteralType::ToString(std::stringstream &ss) const diff --git a/typescript/types/numberLiteralType.h b/checker/types/ts/numberLiteralType.h similarity index 88% rename from typescript/types/numberLiteralType.h rename to checker/types/ts/numberLiteralType.h index e3c3a9a96..b3c34d898 100644 --- a/typescript/types/numberLiteralType.h +++ b/checker/types/ts/numberLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NumberLiteralType : public Type { diff --git a/typescript/types/numberType.cpp b/checker/types/ts/numberType.cpp similarity index 96% rename from typescript/types/numberType.cpp rename to checker/types/ts/numberType.cpp index 0a89535ac..9381711f7 100644 --- a/typescript/types/numberType.cpp +++ b/checker/types/ts/numberType.cpp @@ -16,7 +16,7 @@ #include "numberType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void NumberType::ToString(std::stringstream &ss) const diff --git a/typescript/types/numberType.h b/checker/types/ts/numberType.h similarity index 87% rename from typescript/types/numberType.h rename to checker/types/ts/numberType.h index 702417e77..f8505c863 100644 --- a/typescript/types/numberType.h +++ b/checker/types/ts/numberType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NumberType : public Type { diff --git a/typescript/types/objectDescriptor.cpp b/checker/types/ts/objectDescriptor.cpp similarity index 93% rename from typescript/types/objectDescriptor.cpp rename to checker/types/ts/objectDescriptor.cpp index df7949ba5..6d9ec80ba 100644 --- a/typescript/types/objectDescriptor.cpp +++ b/checker/types/ts/objectDescriptor.cpp @@ -16,8 +16,8 @@ #include "objectDescriptor.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { binder::LocalVariable *ObjectDescriptor::FindProperty(const util::StringView &name) const diff --git a/typescript/types/objectDescriptor.h b/checker/types/ts/objectDescriptor.h similarity index 93% rename from typescript/types/objectDescriptor.h rename to checker/types/ts/objectDescriptor.h index 1d1ba16e5..f852f5014 100644 --- a/typescript/types/objectDescriptor.h +++ b/checker/types/ts/objectDescriptor.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_DESCRIPTOR_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_DESCRIPTOR_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_DESCRIPTOR_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_DESCRIPTOR_H #include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" diff --git a/typescript/types/objectLiteralType.cpp b/checker/types/ts/objectLiteralType.cpp similarity index 94% rename from typescript/types/objectLiteralType.cpp rename to checker/types/ts/objectLiteralType.cpp index 729940cd1..7581f3289 100644 --- a/typescript/types/objectLiteralType.cpp +++ b/checker/types/ts/objectLiteralType.cpp @@ -16,11 +16,11 @@ #include "objectLiteralType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { -class Checker; +class TSChecker; void ObjectLiteralType::ToString(std::stringstream &ss) const { diff --git a/typescript/types/objectLiteralType.h b/checker/types/ts/objectLiteralType.h similarity index 90% rename from typescript/types/objectLiteralType.h rename to checker/types/ts/objectLiteralType.h index a20328d7c..e9b5695c1 100644 --- a/typescript/types/objectLiteralType.h +++ b/checker/types/ts/objectLiteralType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_LITERAL_TYPE_H #include "objectType.h" diff --git a/typescript/types/objectType.cpp b/checker/types/ts/objectType.cpp similarity index 97% rename from typescript/types/objectType.cpp rename to checker/types/ts/objectType.cpp index 966a57af8..fd34d5873 100644 --- a/typescript/types/objectType.cpp +++ b/checker/types/ts/objectType.cpp @@ -15,10 +15,10 @@ #include "objectType.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/interfaceType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/interfaceType.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" namespace panda::es2panda::checker { bool ObjectType::EachSignatureRelatedToSomeSignature(TypeRelation *relation, diff --git a/typescript/types/objectType.h b/checker/types/ts/objectType.h similarity index 96% rename from typescript/types/objectType.h rename to checker/types/ts/objectType.h index 0b07f5a26..3d51d1ed8 100644 --- a/typescript/types/objectType.h +++ b/checker/types/ts/objectType.h @@ -13,12 +13,12 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectDescriptor.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectDescriptor.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" diff --git a/typescript/types/stringLiteralType.cpp b/checker/types/ts/stringLiteralType.cpp similarity index 100% rename from typescript/types/stringLiteralType.cpp rename to checker/types/ts/stringLiteralType.cpp diff --git a/typescript/types/stringLiteralType.h b/checker/types/ts/stringLiteralType.h similarity index 88% rename from typescript/types/stringLiteralType.h rename to checker/types/ts/stringLiteralType.h index 0c9c07826..c4df8c8e4 100644 --- a/typescript/types/stringLiteralType.h +++ b/checker/types/ts/stringLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class StringLiteralType : public Type { diff --git a/typescript/types/stringType.cpp b/checker/types/ts/stringType.cpp similarity index 100% rename from typescript/types/stringType.cpp rename to checker/types/ts/stringType.cpp diff --git a/typescript/types/stringType.h b/checker/types/ts/stringType.h similarity index 87% rename from typescript/types/stringType.h rename to checker/types/ts/stringType.h index 86e746e96..c21499b93 100644 --- a/typescript/types/stringType.h +++ b/checker/types/ts/stringType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class StringType : public Type { diff --git a/typescript/types/tupleType.cpp b/checker/types/ts/tupleType.cpp similarity index 97% rename from typescript/types/tupleType.cpp rename to checker/types/ts/tupleType.cpp index 4358db09c..e6830f28d 100644 --- a/typescript/types/tupleType.cpp +++ b/checker/types/ts/tupleType.cpp @@ -15,10 +15,10 @@ #include "tupleType.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -Type *TupleType::ConvertToArrayType(Checker *checker) +Type *TupleType::ConvertToArrayType(TSChecker *checker) { ArenaVector unionTypes(checker->Allocator()->Adapter()); diff --git a/typescript/types/tupleType.h b/checker/types/ts/tupleType.h similarity index 92% rename from typescript/types/tupleType.h rename to checker/types/ts/tupleType.h index b69978fca..3ee5d44a1 100644 --- a/typescript/types/tupleType.h +++ b/checker/types/ts/tupleType.h @@ -13,14 +13,14 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TUPLE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TUPLE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TUPLE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TUPLE_TYPE_H #include "macros.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/elementFlags.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/elementFlags.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" namespace panda::es2panda::checker { using NamedTupleMemberPool = std::unordered_map; @@ -101,7 +101,7 @@ public: return res->second; } - Type *ConvertToArrayType(Checker *checker); + Type *ConvertToArrayType(TSChecker *checker); void ToString(std::stringstream &ss) const override; void Identical(TypeRelation *relation, Type *other) override; diff --git a/typescript/types/typeParameter.cpp b/checker/types/ts/typeParameter.cpp similarity index 100% rename from typescript/types/typeParameter.cpp rename to checker/types/ts/typeParameter.cpp diff --git a/typescript/types/typeParameter.h b/checker/types/ts/typeParameter.h similarity index 90% rename from typescript/types/typeParameter.h rename to checker/types/ts/typeParameter.h index fe30e2cdc..2b6a51dd2 100644 --- a/typescript/types/typeParameter.h +++ b/checker/types/ts/typeParameter.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_PARAMETER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_PARAMETER_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_PARAMETER_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_PARAMETER_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class TypeParameter : public Type { diff --git a/typescript/types/typeReference.cpp b/checker/types/ts/typeReference.cpp similarity index 100% rename from typescript/types/typeReference.cpp rename to checker/types/ts/typeReference.cpp diff --git a/typescript/types/typeReference.h b/checker/types/ts/typeReference.h similarity index 84% rename from typescript/types/typeReference.h rename to checker/types/ts/typeReference.h index aa90e1c70..9b7c47f12 100644 --- a/typescript/types/typeReference.h +++ b/checker/types/ts/typeReference.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class TypeReference : public Type { @@ -44,4 +44,4 @@ private: }; } // namespace panda::es2panda::checker -#endif /* ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H */ +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H */ diff --git a/typescript/types/types.h b/checker/types/ts/types.h similarity index 89% rename from typescript/types/types.h rename to checker/types/ts/types.h index 7b3d98100..404ed5af8 100644 --- a/typescript/types/types.h +++ b/checker/types/ts/types.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_H #include "anyType.h" #include "arrayType.h" @@ -42,8 +42,8 @@ #include "unknownType.h" #include "voidType.h" #include "indexInfo.h" -#include "signature.h" #include "typeParameter.h" #include "typeReference.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" #endif /* TYPES_H */ diff --git a/typescript/types/undefinedType.cpp b/checker/types/ts/undefinedType.cpp similarity index 100% rename from typescript/types/undefinedType.cpp rename to checker/types/ts/undefinedType.cpp diff --git a/typescript/types/undefinedType.h b/checker/types/ts/undefinedType.h similarity index 87% rename from typescript/types/undefinedType.h rename to checker/types/ts/undefinedType.h index 64cdef883..d58e4561f 100644 --- a/typescript/types/undefinedType.h +++ b/checker/types/ts/undefinedType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNDEFINED_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNDEFINED_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNDEFINED_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNDEFINED_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class UndefinedType : public Type { diff --git a/typescript/types/unionType.cpp b/checker/types/ts/unionType.cpp similarity index 98% rename from typescript/types/unionType.cpp rename to checker/types/ts/unionType.cpp index 9bb413659..b408ae424 100644 --- a/typescript/types/unionType.cpp +++ b/checker/types/ts/unionType.cpp @@ -16,7 +16,7 @@ #include "unionType.h" #include -#include "plugins/ecmascript/es2panda/typescript/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" namespace panda::es2panda::checker { void UnionType::ToString(std::stringstream &ss) const diff --git a/typescript/types/unionType.h b/checker/types/ts/unionType.h similarity index 96% rename from typescript/types/unionType.h rename to checker/types/ts/unionType.h index 70e185017..90222f83e 100644 --- a/typescript/types/unionType.h +++ b/checker/types/ts/unionType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNION_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNION_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNION_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class GlobalTypesHolder; diff --git a/typescript/types/unknownType.cpp b/checker/types/ts/unknownType.cpp similarity index 100% rename from typescript/types/unknownType.cpp rename to checker/types/ts/unknownType.cpp diff --git a/typescript/types/unknownType.h b/checker/types/ts/unknownType.h similarity index 87% rename from typescript/types/unknownType.h rename to checker/types/ts/unknownType.h index 892b81655..205e1e501 100644 --- a/typescript/types/unknownType.h +++ b/checker/types/ts/unknownType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNKNOWN_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNKNOWN_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNKNOWN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNKNOWN_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class UnknownType : public Type { diff --git a/typescript/types/voidType.cpp b/checker/types/ts/voidType.cpp similarity index 100% rename from typescript/types/voidType.cpp rename to checker/types/ts/voidType.cpp diff --git a/typescript/types/voidType.h b/checker/types/ts/voidType.h similarity index 87% rename from typescript/types/voidType.h rename to checker/types/ts/voidType.h index 9f8fcfd2c..2776c0d5b 100644 --- a/typescript/types/voidType.h +++ b/checker/types/ts/voidType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_VOID_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_VOID_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_VOID_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_VOID_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class VoidType : public Type { diff --git a/typescript/types/type.cpp b/checker/types/type.cpp similarity index 63% rename from typescript/types/type.cpp rename to checker/types/type.cpp index 4d4ba4b5b..edb3b5669 100644 --- a/typescript/types/type.cpp +++ b/checker/types/type.cpp @@ -15,11 +15,21 @@ #include "type.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeFlag.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeFacts.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/typeFlag.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/stsObjectType.h" namespace panda::es2panda::checker { +bool Type::IsSTSNullType() const +{ + return IsSTSObjectType() && AsSTSObjectType()->HasObjectFlag(STSObjectFlags::NULL_TYPE); +} + +bool Type::IsSTSStringType() const +{ + return IsSTSObjectType() && AsSTSObjectType()->HasObjectFlag(STSObjectFlags::STRING); +} + void Type::ToStringAsSrc(std::stringstream &ss) const { ToString(ss); @@ -35,8 +45,20 @@ bool Type::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unu return false; } +TypeFacts Type::GetTypeFacts() const +{ + return TypeFacts::NONE; +} + void Type::Compare([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *other) {} +void Type::IsSubtype([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *Type::AsSuper([[maybe_unused]] Checker *checker, [[maybe_unused]] binder::Variable *sourceVar) +{ + return nullptr; +} + Type *Type::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, [[maybe_unused]] GlobalTypesHolder *globalTypes) { diff --git a/typescript/types/type.h b/checker/types/type.h similarity index 69% rename from typescript/types/type.h rename to checker/types/type.h index c0411b81c..3aa861967 100644 --- a/typescript/types/type.h +++ b/checker/types/type.h @@ -13,12 +13,13 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_H -#include "plugins/ecmascript/es2panda/typescript/types/typeFacts.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeMapping.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" +#include "generated/signatures.h" +#include "plugins/ecmascript/es2panda/checker/types/typeMapping.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/typeFacts.h" #include "macros.h" #include @@ -36,6 +37,7 @@ class GlobalTypesHolder; #define DECLARE_TYPENAMES(typeFlag, typeName) class typeName; TYPE_MAPPING(DECLARE_TYPENAMES) #undef DECLARE_TYPENAMES +class STSStringType; class Type { public: @@ -74,24 +76,39 @@ public: TYPE_MAPPING(TYPE_AS_CASTS) #undef TYPE_AS_CASTS + bool IsSTSStringType() const; + bool IsSTSNullType() const; + + STSStringType *AsSTSStringType() + { + ASSERT(IsSTSObjectType()); + return reinterpret_cast(this); + } + + const STSStringType *AsSTSStringType() const + { + ASSERT(IsSTSObjectType()); + return reinterpret_cast(this); + } + TypeFlag TypeFlags() const { return typeFlags_; } - bool HasTypeFlag(TypeFlag type_flag) const + bool HasTypeFlag(TypeFlag typeflag) const { - return (typeFlags_ & type_flag) != 0; + return (typeFlags_ & typeflag) != 0; } - void AddTypeFlag(TypeFlag type_flag) + void AddTypeFlag(TypeFlag typeflag) { - typeFlags_ |= type_flag; + typeFlags_ |= typeflag; } - void RemoveTypeFlag(TypeFlag type_flag) + void RemoveTypeFlag(TypeFlag typeflag) { - typeFlags_ &= ~type_flag; + typeFlags_ &= ~typeflag; } uint64_t Id() const @@ -114,16 +131,30 @@ public: return variable_; } + util::StringView ToAssemblerTypeView(ArenaAllocator *allocator) const + { + std::stringstream ss; + ToAssemblerType(ss); + return util::UString(ss.str(), allocator).View(); + } + virtual void ToString(std::stringstream &ss) const = 0; virtual void ToStringAsSrc(std::stringstream &ss) const; - virtual TypeFacts GetTypeFacts() const = 0; + virtual TypeFacts GetTypeFacts() const; + virtual void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const {}; + virtual uint32_t Rank() const + { + return 0; + } virtual void Identical(TypeRelation *relation, Type *other); virtual void AssignmentTarget(TypeRelation *relation, Type *source) = 0; virtual bool AssignmentSource(TypeRelation *relation, Type *target); virtual void Compare(TypeRelation *relation, Type *other); + virtual void IsSubtype(TypeRelation *relation, Type *source); + virtual Type *AsSuper(Checker *checker, binder::Variable *sourceVar); - virtual Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) = 0; + virtual Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) diff --git a/typescript/types/typeFacts.h b/checker/types/typeFacts.h similarity index 98% rename from typescript/types/typeFacts.h rename to checker/types/typeFacts.h index 3a92604a7..2c0ec6620 100644 --- a/typescript/types/typeFacts.h +++ b/checker/types/typeFacts.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_FACTS_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_FACTS_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FACTS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FACTS_H #include "plugins/ecmascript/es2panda/util/enumbitops.h" diff --git a/checker/types/typeFlag.h b/checker/types/typeFlag.h new file mode 100644 index 000000000..5fedd45d4 --- /dev/null +++ b/checker/types/typeFlag.h @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FLAG_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FLAG_H + +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +#include + +namespace panda::es2panda::checker { +enum class TypeFlag : uint64_t { + NONE = 0, + NUMBER = 1ULL << 0, // x: number + STRING = 1ULL << 1, // x: string + BOOLEAN = 1ULL << 2, // x: boolean + VOID = 1ULL << 3, // x: void + NULL_TYPE = 1ULL << 4, // x: null + UNDEFINED = 1ULL << 5, // x: undefined + UNKNOWN = 1ULL << 6, // x: unknown + NEVER = 1ULL << 7, // x: never + UNION = 1ULL << 8, // x: a | b + OBJECT = 1ULL << 9, // x: object + BIGINT = 1ULL << 10, // x: bigint + BOOLEAN_LITERAL = 1ULL << 11, // x: true + NUMBER_LITERAL = 1ULL << 12, // x: 10 + STRING_LITERAL = 1ULL << 13, // x: "foo" + BIGINT_LITERAL = 1ULL << 14, // x: 10n + ENUM = 1ULL << 15, // enum x + ENUM_LITERAL = 1ULL << 16, // member of enum + SYMBOL = 1ULL << 17, // x: symbol + UNIQUE_SYMBOL = 1ULL << 18, // one of JS unique symbols + TYPE_PARAMETER = 1ULL << 19, // function + INTERSECTION = 1ULL << 20, // x: a & b + INDEX = 1ULL << 21, // keyof x + INDEX_ACCESS = 1ULL << 22, // x[a] + CONDITIONAL = 1ULL << 23, // x extends a ? b : c + SUBSTITUTION = 1ULL << 24, // type parameter substitution + TEMPLATE_LITERAL = 1ULL << 25, // x: `hello ${World}` + STRING_MAPPING = 1ULL << 27, // Uppercase/Lowercase type + ANY = 1ULL << 28, // x: any + ARRAY = 1ULL << 29, // x: number[] + FUNCTION = 1ULL << 30, // x: (a) => b + NON_PRIMITIVE = 1ULL << 31, // x: object + TYPE_REFERENCE = 1ULL << 32, // x: A + READONLY = 1ULL << 33, // type assigned to a readonly property + CONSTANT = 1ULL << 34, // type for constant expressions containing the associated constant value + BYTE = 1ULL << 35, // x: byte + SHORT = 1ULL << 36, // x: short + INT = 1ULL << 37, // x: int + LONG = 1ULL << 38, // x: long + FLOAT = 1ULL << 39, // x: float + DOUBLE = 1ULL << 40, // x: double + CHAR = 1ULL << 41, // x: char + STS_BOOLEAN = 1ULL << 42, // STS boolean type + STS_VOID = 1ULL << 43, // STS void type + STS_OBJECT = 1ULL << 44, // STS class or interface type + STS_ARRAY = 1ULL << 45, // STS array type + SYNTHETIC = 1ULL < 46, // STS type parameter + WILDCARD = 1ULL << 47, // new A() + STS_TYPE_PARAMETER = 1ULL < 48, // STS type parameter + STS_TYPE_REFERENCE = 1ULL < 49, // STS type parameter + STS_TYPE = BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | CHAR | STS_BOOLEAN | STS_VOID | STS_OBJECT | STS_ARRAY | + WILDCARD | STS_TYPE_PARAMETER, + STS_PRIMITIVE = BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | CHAR | STS_BOOLEAN, + STS_ARRAY_INDEX = BYTE | SHORT | INT, + STS_INTEGRAL = BYTE | CHAR | SHORT | INT | LONG, + STS_FLOATING_POINT = FLOAT | DOUBLE, + STS_NUMERIC = STS_INTEGRAL | FLOAT | DOUBLE, + STS_ARRAY_OR_OBJECT = STS_ARRAY | STS_OBJECT, + STS_WIDE_NUMERIC = LONG | DOUBLE, + NARROWABLE_TO_FLOAT = DOUBLE, + NARROWABLE_TO_LONG = FLOAT | NARROWABLE_TO_FLOAT, + NARROWABLE_TO_INT = LONG | NARROWABLE_TO_LONG, + NARROWABLE_TO_CHAR = SHORT | INT | NARROWABLE_TO_INT, + NARROWABLE_TO_SHORT = INT | NARROWABLE_TO_INT, + NARROWABLE_TO_BYTE = CHAR | NARROWABLE_TO_CHAR, + WIDENABLE_TO_SHORT = BYTE, + WIDENABLE_TO_INT = CHAR | SHORT | WIDENABLE_TO_SHORT, + WIDENABLE_TO_LONG = INT | WIDENABLE_TO_INT, + WIDENABLE_TO_FLOAT = LONG | WIDENABLE_TO_LONG, + WIDENABLE_TO_DOUBLE = WIDENABLE_TO_FLOAT, + COMPUTED_TYPE_LITERAL_NAME = STRING_LITERAL | NUMBER_LITERAL | ENUM, + COMPUTED_NAME = COMPUTED_TYPE_LITERAL_NAME | STRING | NUMBER | ANY | SYMBOL, + ANY_OR_UNKNOWN = ANY | UNKNOWN, + ANY_OR_VOID = ANY | VOID, + NULLABLE = UNDEFINED | NULL_TYPE, + ANY_OR_NULLABLE = ANY | NULLABLE, + LITERAL = NUMBER_LITERAL | BOOLEAN_LITERAL | STRING_LITERAL | BIGINT_LITERAL, + NUMBER_LIKE = NUMBER | NUMBER_LITERAL, + NUMBER_LIKE_ENUM = NUMBER_LIKE | ENUM, + STRING_LIKE = STRING | STRING_LITERAL, + BOOLEAN_LIKE = BOOLEAN | BOOLEAN_LITERAL, + BIGINT_LIKE = BIGINT | BIGINT_LITERAL, + VOID_LIKE = VOID | UNDEFINED, + NUMBER_OR_ANY = NUMBER | ANY, + PRIMITIVE = STRING | NUMBER | BIGINT | BOOLEAN | ENUM | ENUM_LITERAL | SYMBOL | VOID | UNDEFINED | NULL_TYPE | + LITERAL | UNIQUE_SYMBOL, + PRIMITIVE_OR_ANY = PRIMITIVE | ANY, + UNION_OR_INTERSECTION = UNION | INTERSECTION, + DEFINITELY_FALSY = + STRING_LITERAL | NUMBER_LITERAL | BOOLEAN_LITERAL | BIGINT_LITERAL | VOID | UNDEFINED | NULL_TYPE, + POSSIBLY_FALSY = DEFINITELY_FALSY | STRING | NUMBER | BOOLEAN | BIGINT, + VALID_ARITHMETIC_TYPE = ANY | NUMBER_LIKE | BIGINT_LIKE | ENUM, + UNIT = LITERAL | UNIQUE_SYMBOL | NULLABLE, +}; + +DEFINE_BITOPS(TypeFlag) +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_TYPE_FLAG_H */ diff --git a/checker/types/typeMapping.h b/checker/types/typeMapping.h new file mode 100644 index 000000000..0fad9ad9a --- /dev/null +++ b/checker/types/typeMapping.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_MAPPING_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_MAPPING_H + +#include "typeFlag.h" + +#define TYPE_MAPPING(_) \ + _(TypeFlag::ARRAY, ArrayType) \ + _(TypeFlag::ANY, AnyType) \ + _(TypeFlag::BIGINT_LITERAL, BigintLiteralType) \ + _(TypeFlag::NUMBER, NumberType) \ + _(TypeFlag::STRING, StringType) \ + _(TypeFlag::BOOLEAN, BooleanType) \ + _(TypeFlag::VOID, VoidType) \ + _(TypeFlag::NULL_TYPE, NullType) \ + _(TypeFlag::UNDEFINED, UndefinedType) \ + _(TypeFlag::UNKNOWN, UnknownType) \ + _(TypeFlag::NEVER, NeverType) \ + _(TypeFlag::UNION, UnionType) \ + _(TypeFlag::OBJECT, ObjectType) \ + _(TypeFlag::BIGINT, BigintType) \ + _(TypeFlag::BOOLEAN_LITERAL, BooleanLiteralType) \ + _(TypeFlag::NUMBER_LITERAL, NumberLiteralType) \ + _(TypeFlag::STRING_LITERAL, StringLiteralType) \ + _(TypeFlag::ENUM, EnumType) \ + _(TypeFlag::ENUM_LITERAL, EnumLiteralType) \ + _(TypeFlag::TYPE_PARAMETER, TypeParameter) \ + _(TypeFlag::TYPE_REFERENCE, TypeReference) \ + _(TypeFlag::BYTE, ByteType) \ + _(TypeFlag::SHORT, ShortType) \ + _(TypeFlag::INT, IntType) \ + _(TypeFlag::LONG, LongType) \ + _(TypeFlag::FLOAT, FloatType) \ + _(TypeFlag::DOUBLE, DoubleType) \ + _(TypeFlag::CHAR, CharType) \ + _(TypeFlag::STS_BOOLEAN, STSBooleanType) \ + _(TypeFlag::STS_VOID, STSVoidType) \ + _(TypeFlag::FUNCTION, STSFunctionType) \ + _(TypeFlag::STS_OBJECT, STSObjectType) \ + _(TypeFlag::STS_ARRAY, STSArrayType) \ + _(TypeFlag::NON_PRIMITIVE, NonPrimitiveType) \ + _(TypeFlag::WILDCARD, WildcardType) \ + _(TypeFlag::STS_TYPE_PARAMETER, STSTypeParameter) \ + _(TypeFlag::STS_TYPE_REFERENCE, STSTypeReference) + +#define OBJECT_TYPE_MAPPING(_) \ + _(ObjectType::ObjectTypeKind::FUNCTION, FunctionType) \ + _(ObjectType::ObjectTypeKind::TUPLE, TupleType) \ + _(ObjectType::ObjectTypeKind::LITERAL, ObjectLiteralType) \ + _(ObjectType::ObjectTypeKind::INTERFACE, InterfaceType) + +#endif /* TYPE_MAPPING_H */ diff --git a/typescript/types/typeRelation.cpp b/checker/types/typeRelation.cpp similarity index 84% rename from typescript/types/typeRelation.cpp rename to checker/types/typeRelation.cpp index da3491542..73e1aefdb 100644 --- a/typescript/types/typeRelation.cpp +++ b/checker/types/typeRelation.cpp @@ -15,33 +15,11 @@ #include "typeRelation.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { -const Type *AsSrc::GetType() const -{ - return type_; -} - -TypeRelation::TypeRelation(Checker *checker) : checker_(checker) {} - -bool TypeRelation::IsTrue() const -{ - return result_ == RelationResult::TRUE; -} - -const Checker *TypeRelation::GetChecker() const -{ - return checker_; -} - -Checker *TypeRelation::GetChecker() -{ - return checker_; -} - ArenaAllocator *TypeRelation::Allocator() { return checker_->Allocator(); @@ -116,6 +94,7 @@ bool TypeRelation::IsIdenticalTo(IndexInfo *source, IndexInfo *target) return result_ == RelationResult::TRUE; } +// TODO: applyNarrowing -> flag bool TypeRelation::IsAssignableTo(Type *source, Type *target) { result_ = CacheLookup(source, target, checker_->AssignableResults(), RelationType::ASSIGNABLE); @@ -130,8 +109,10 @@ bool TypeRelation::IsAssignableTo(Type *source, Type *target) target->AssignmentTarget(this, source); } - checker_->AssignableResults().cached.insert( - {{source->Id(), target->Id()}, {result_, RelationType::ASSIGNABLE}}); + if (flags_ == TypeRelationFlag::NONE) { + checker_->AssignableResults().cached.insert( + {{source->Id(), target->Id()}, {result_, RelationType::ASSIGNABLE}}); + } } return result_ == RelationResult::TRUE; @@ -165,9 +146,4 @@ void TypeRelation::RaiseError(std::initializer_list lis { checker_->ThrowTypeError(list, loc); } - -void TypeRelation::Result(bool res) -{ - result_ = res ? RelationResult::TRUE : RelationResult::FALSE; -} } // namespace panda::es2panda::checker diff --git a/typescript/types/typeRelation.h b/checker/types/typeRelation.h similarity index 50% rename from typescript/types/typeRelation.h rename to checker/types/typeRelation.h index c55b30ea1..2f0792989 100644 --- a/typescript/types/typeRelation.h +++ b/checker/types/typeRelation.h @@ -13,27 +13,53 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_RELATION_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_RELATION_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H #include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" #include "plugins/ecmascript/es2panda/lexer/token/tokenType.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +#include "macros.h" #include #include +namespace panda::es2panda::ir { +class Expression; +} + namespace panda::es2panda::checker { class Signature; class IndexInfo; class Type; class Checker; -enum class RelationResult { TRUE, FALSE, UNKNOWN, MAYBE, CACHE_MISS }; +enum class TypeRelationFlag { + NONE = 0, + NARROWING = 1 << 0, + WIDENING = 1 << 1, + BOXING = 1 << 2, + UNBOXING = 1 << 3, + CAPTURE = 1 << 4, + STRING = 1 << 5, + VALUE_SET = 1 << 6, + UNCHECKED = 1 << 7, + NO_THROW = 1 << 8, + SELF_REFERENCE = 1 << 9, + NO_RETURN_TYPE_CHECK = 1 << 10, + DIRECT_RETURN = 1 << 11, + + ASSIGNMENT_CONTEXT = WIDENING | BOXING | UNBOXING, +}; + +enum class RelationResult { TRUE, FALSE, UNKNOWN, MAYBE, CACHE_MISS, ERROR }; enum class RelationType { COMPARABLE, ASSIGNABLE, IDENTICAL }; +DEFINE_BITOPS(TypeRelationFlag) + class RelationKey { public: uint64_t sourceId; @@ -74,17 +100,66 @@ class AsSrc { public: explicit AsSrc(const Type *type) : type_(const_cast(type)) {} - const Type *GetType() const; + const Type *GetType() const + { + return type_; + } private: Type *type_; }; -using TypeErrorMessageElement = std::variant; +using TypeErrorMessageElement = + std::variant; class TypeRelation { public: - explicit TypeRelation(Checker *checker); + explicit TypeRelation(Checker *checker) : checker_(checker), result_(RelationResult::FALSE) {} + + bool IsTrue() const + { + return result_ == RelationResult::TRUE; + } + + bool IsError() const + { + return result_ == RelationResult::ERROR; + } + + bool ApplyNarrowing() const + { + return (flags_ & TypeRelationFlag::NARROWING) != 0; + } + + bool ApplyWidening() const + { + return (flags_ & TypeRelationFlag::WIDENING) != 0; + } + + bool NoReturnTypeCheck() const + { + return (flags_ & TypeRelationFlag::NO_RETURN_TYPE_CHECK) != 0; + } + + bool DirectReturn() const + { + return (flags_ & TypeRelationFlag::DIRECT_RETURN) != 0; + } + + const Checker *GetChecker() const + { + return checker_; + } + + ir::Expression *GetNode() const + { + return node_; + } + + Checker *GetChecker() + { + return checker_; + } bool IsIdenticalTo(Type *source, Type *target); bool IsIdenticalTo(Signature *source, Signature *target); @@ -94,18 +169,58 @@ public: void RaiseError(const std::string &errMsg, const lexer::SourcePosition &loc) const; void RaiseError(std::initializer_list list, const lexer::SourcePosition &loc) const; - void Result(bool res); - const Checker *GetChecker() const; - Checker *GetChecker(); + void Result(bool res) + { + result_ = res ? RelationResult::TRUE : RelationResult::FALSE; + } + + void Result(RelationResult res) + { + result_ = res; + } + + void SetNode(ir::Expression *node) + { + node_ = node; + } + + void SetFlags(TypeRelationFlag flags) + { + flags_ = flags; + } + ArenaAllocator *Allocator(); - bool IsTrue() const; + + friend class SavedTypeRelationFlagsContext; private: RelationResult CacheLookup(const Type *source, const Type *target, const RelationHolder &holder, RelationType type) const; Checker *checker_; - RelationResult result_ {RelationResult::FALSE}; + RelationResult result_ {}; + TypeRelationFlag flags_ {}; + ir::Expression *node_ {}; +}; +class SavedTypeRelationFlagsContext { +public: + explicit SavedTypeRelationFlagsContext(TypeRelation *relation, TypeRelationFlag newFlag) + : relation_(relation), prev_(relation->flags_) + { + relation_->flags_ = newFlag; + } + + NO_COPY_SEMANTIC(SavedTypeRelationFlagsContext); + DEFAULT_MOVE_SEMANTIC(SavedTypeRelationFlagsContext); + + ~SavedTypeRelationFlagsContext() + { + relation_->flags_ = prev_; + } + +private: + TypeRelation *relation_; + TypeRelationFlag prev_; }; } // namespace panda::es2panda::checker diff --git a/compiler/base/catchTable.cpp b/compiler/base/catchTable.cpp index b6992dd74..eda1103bb 100644 --- a/compiler/base/catchTable.cpp +++ b/compiler/base/catchTable.cpp @@ -18,8 +18,8 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" namespace panda::es2panda::compiler { -TryLabelSet::TryLabelSet(PandaGen *pg) - : try_(pg->AllocLabel(), pg->AllocLabel()), catch_(pg->AllocLabel(), pg->AllocLabel()) +TryLabelSet::TryLabelSet(CodeGen *cg) + : try_(cg->AllocLabel(), cg->AllocLabel()), catch_(cg->AllocLabel(), cg->AllocLabel()) { } } // namespace panda::es2panda::compiler diff --git a/compiler/base/catchTable.h b/compiler/base/catchTable.h index 5dfd29a23..50236a066 100644 --- a/compiler/base/catchTable.h +++ b/compiler/base/catchTable.h @@ -20,11 +20,11 @@ #include "plugins/ecmascript/es2panda/compiler/core/labelPair.h" namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class TryLabelSet { public: - explicit TryLabelSet(PandaGen *pg); + explicit TryLabelSet(CodeGen *cg); ~TryLabelSet() = default; DEFAULT_COPY_SEMANTIC(TryLabelSet); @@ -67,7 +67,7 @@ private: class CatchTable { public: - CatchTable(PandaGen *pg, uint32_t depth) : labelSet_(pg), depth_(depth) {} + CatchTable(CodeGen *cg, uint32_t depth) : labelSet_(cg), depth_(depth) {} ~CatchTable() = default; NO_COPY_SEMANTIC(CatchTable); diff --git a/compiler/base/condition.cpp b/compiler/base/condition.cpp index 647f20923..b5c26bbe0 100644 --- a/compiler/base/condition.cpp +++ b/compiler/base/condition.cpp @@ -16,6 +16,7 @@ #include "condition.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/STSGen.h" #include "plugins/ecmascript/es2panda/ir/expressions/binaryExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/unaryExpression.h" @@ -89,4 +90,76 @@ void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLa pg->ToBoolean(expr); pg->BranchIfFalse(expr, falseLabel); } + +Condition::Result Condition::CheckConstantExpr(const ir::Expression *expr) +{ + if (expr->TsType()->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + auto res = expr->TsType()->AsSTSBooleanType()->GetValue(); + return res ? Result::CONST_TRUE : Result::CONST_FALSE; + } + + return Result::UNKNOWN; +} + +void Condition::Compile(STSGen *stsg, const ir::Expression *expr, Label *falseLabel) +{ + if (expr->IsBinaryExpression()) { + const auto *binExpr = expr->AsBinaryExpression(); + + switch (binExpr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: + case lexer::TokenType::KEYW_INSTANCEOF: { + auto ttctx = TargetTypeContext(stsg, binExpr->OperationType()); + + RegScope rs(stsg); + VReg lhs = stsg->AllocReg(); + + binExpr->Left()->Compile(stsg); + stsg->ApplyWidenAndStoreAccumulator(binExpr, lhs, binExpr->OperationType()); + binExpr->Right()->Compile(stsg); + stsg->Condition(binExpr, binExpr->OperatorType(), lhs, falseLabel); + return; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { + binExpr->Left()->Compile(stsg); + stsg->BranchIfFalse(binExpr, falseLabel); + + binExpr->Right()->Compile(stsg); + stsg->BranchIfFalse(binExpr, falseLabel); + return; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + auto *endLabel = stsg->AllocLabel(); + + binExpr->Left()->Compile(stsg); + stsg->BranchIfTrue(binExpr, endLabel); + + binExpr->Right()->Compile(stsg); + stsg->BranchIfFalse(binExpr, falseLabel); + stsg->SetLabel(binExpr, endLabel); + return; + } + default: { + break; + } + } + } else if (expr->IsUnaryExpression() && + expr->AsUnaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) { + expr->AsUnaryExpression()->Argument()->Compile(stsg); + stsg->BranchIfTrue(expr, falseLabel); + return; + } + + // TODO: Handle implicit bool conversion: not zero int == true, not null obj ref == true, otherwise false + ASSERT(expr->TsType()->IsSTSBooleanType()); // already checked by checker::CheckTruthinessOfType() + expr->Compile(stsg); + stsg->BranchIfFalse(expr, falseLabel); + + return; +} } // namespace panda::es2panda::compiler diff --git a/compiler/base/condition.h b/compiler/base/condition.h index c7d8e655d..af01495a5 100644 --- a/compiler/base/condition.h +++ b/compiler/base/condition.h @@ -20,13 +20,22 @@ namespace panda::es2panda::compiler { class PandaGen; +class STSGen; class Label; class Condition { public: Condition() = delete; + enum class Result { + CONST_TRUE, + CONST_FALSE, + UNKNOWN, + }; + static void Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLabel); + static void Compile(STSGen *stsg, const ir::Expression *expr, Label *falseLabel); + static Result CheckConstantExpr(const ir::Expression *expr); }; } // namespace panda::es2panda::compiler diff --git a/compiler/base/destructuring.cpp b/compiler/base/destructuring.cpp index ea61f4d3d..694faf5c2 100644 --- a/compiler/base/destructuring.cpp +++ b/compiler/base/destructuring.cpp @@ -40,7 +40,7 @@ static void GenRestElement(PandaGen *pg, const ir::SpreadElement *restElement, DestructuringRestIterator iterator(destIterator); // create left reference for rest element - LReference lref = LReference::CreateLRef(pg, restElement, isDeclaration); + auto lref = JSLReference::Create(pg, restElement, isDeclaration); // create an empty array first pg->CreateEmptyArray(restElement); @@ -104,7 +104,7 @@ static void GenArray(PandaGen *pg, const ir::ArrayExpression *array) init = element->AsAssignmentPattern()->Right(); } - LReference lref = LReference::CreateLRef(pg, target, array->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, array->IsDeclaration()); iterator.Step(); if (init != nullptr) { @@ -192,7 +192,7 @@ static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, for (const auto *element : properties) { if (element->IsRestElement()) { RegScope restScope(pg); - LReference lref = LReference::CreateLRef(pg, element, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, element, object->IsDeclaration()); pg->CreateObjectWithExcludedKeys(element, rhs, propStart, properties.size() - 1); lref.SetValue(); break; @@ -214,7 +214,7 @@ static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, pg->StoreAccumulator(key, propReg); - LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, object->IsDeclaration()); pg->LoadAccumulator(element, propReg); pg->LoadObjByValue(element, rhs); @@ -252,7 +252,7 @@ static void GenObject(PandaGen *pg, const ir::ObjectExpression *object, VReg rhs Operand propOperand = pg->ToOwnPropertyKey(key, propExpr->IsComputed()); - LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, object->IsDeclaration()); if (std::holds_alternative(propOperand)) { pg->LoadAccumulator(element, std::get(propOperand)); diff --git a/compiler/base/literals.h b/compiler/base/literals.h index 9534b8305..bb2b73b01 100644 --- a/compiler/base/literals.h +++ b/compiler/base/literals.h @@ -27,7 +27,7 @@ class TaggedTemplateExpression; } // namespace panda::es2panda::ir namespace panda::es2panda::checker { -class Checker; +class TSChecker; class Type; } // namespace panda::es2panda::checker diff --git a/compiler/base/lreference.cpp b/compiler/base/lreference.cpp index 0f2e0b36f..0784ef98c 100644 --- a/compiler/base/lreference.cpp +++ b/compiler/base/lreference.cpp @@ -19,7 +19,10 @@ #include "plugins/ecmascript/es2panda/compiler/base/destructuring.h" #include "plugins/ecmascript/es2panda/compiler/core/function.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/STSGen.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" @@ -28,11 +31,45 @@ #include "plugins/ecmascript/es2panda/util/helpers.h" namespace panda::es2panda::compiler { -// LReference -LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind, - binder::ScopeFindResult res) - : node_(node), pg_(pg), refKind_(refKind), res_(res), isDeclaration_(isDeclaration) +LReference::LReferenceBase LReference::CreateBase(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) +{ + switch (node->Type()) { + case ir::AstNodeType::IDENTIFIER: { + const util::StringView &name = node->AsIdentifier()->Name(); + binder::ScopeFindResult res = cg->Scope()->Find(name); + + return {cg, node, ReferenceKind::VAR_OR_GLOBAL, res, isDeclaration}; + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + return {cg, node, ReferenceKind::MEMBER, {}, false}; + } + case ir::AstNodeType::VARIABLE_DECLARATION: { + ASSERT(node->AsVariableDeclaration()->Declarators().size() == 1); + return CreateBase(cg, node->AsVariableDeclaration()->Declarators()[0]->Id(), true); + } + case ir::AstNodeType::VARIABLE_DECLARATOR: { + return CreateBase(cg, node->AsVariableDeclarator()->Id(), true); + } + case ir::AstNodeType::ARRAY_PATTERN: + case ir::AstNodeType::OBJECT_PATTERN: { + return {cg, node, ReferenceKind::DESTRUCTURING, {}, isDeclaration}; + } + case ir::AstNodeType::ASSIGNMENT_PATTERN: { + return CreateBase(cg, node->AsAssignmentPattern()->Left(), true); + } + case ir::AstNodeType::REST_ELEMENT: { + return CreateBase(cg, node->AsRestElement()->Argument(), true); + } + default: { + UNREACHABLE(); + } + } +} + +JSLReference::JSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration) + : LReference(node, refKind, res, isDeclaration), pg_(static_cast(cg)) { if (refKind_ != ReferenceKind::MEMBER) { return; @@ -50,7 +87,7 @@ LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration obj_ = pg_->AllocReg(); memberExpr->Object()->Compile(pg_); - pg->StoreAccumulator(node_, obj_); + pg_->StoreAccumulator(node_, obj_); prop_ = pg_->ToNamedPropertyKey(memberExpr->Property(), memberExpr->IsComputed()); if (std::holds_alternative(prop_)) { @@ -68,7 +105,7 @@ LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration prop_ = propReg; } -void LReference::GetValue() +void JSLReference::GetValue() const { switch (refKind_) { case ReferenceKind::VAR_OR_GLOBAL: { @@ -96,7 +133,7 @@ void LReference::GetValue() } } -void LReference::SetValue() +void JSLReference::SetValue() const { switch (refKind_) { case ReferenceKind::VAR_OR_GLOBAL: { @@ -127,48 +164,102 @@ void LReference::SetValue() } } -ReferenceKind LReference::Kind() const +STSLReference::STSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration) + : LReference(node, refKind, res, isDeclaration), stsg_(static_cast(cg)) { - return refKind_; -} + if (refKind_ != ReferenceKind::MEMBER) { + refKind_ = ResolveReferenceKind(res.variable); + return; + } -binder::Variable *LReference::Variable() const -{ - return res_.variable; + const auto *memberExpr = node_->AsMemberExpression(); + staticObjRef_ = memberExpr->Object()->TsType(); + + if (!memberExpr->IsComputed() && memberExpr->PropVar()->HasFlag(binder::VariableFlags::STATIC)) { + return; + } + + TargetTypeContext ttctx(stsg_, memberExpr->Object()->TsType()); + memberExpr->Object()->Compile(stsg_); + baseReg_ = stsg_->AllocReg(); + stsg_->StoreAccumulator(node, baseReg_); + + if (memberExpr->IsComputed()) { + TargetTypeContext pttctx(stsg_, memberExpr->Property()->TsType()); + memberExpr->Property()->Compile(stsg_); + propReg_ = stsg_->AllocReg(); + stsg_->StoreAccumulator(node, propReg_); + } } -LReference LReference::CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration) +ReferenceKind STSLReference::ResolveReferenceKind(const binder::Variable *variable) { - switch (node->Type()) { - case ir::AstNodeType::IDENTIFIER: { - const util::StringView &name = node->AsIdentifier()->Name(); - binder::ScopeFindResult res = pg->Scope()->Find(name); + auto *declNode = variable->Declaration()->Node(); - return {node, pg, isDeclaration, ReferenceKind::VAR_OR_GLOBAL, res}; + switch (declNode->Type()) { + case ir::AstNodeType::CLASS_PROPERTY: { + auto *classField = declNode->AsClassProperty(); + return classField->IsStatic() ? ReferenceKind::STATIC_FIELD : ReferenceKind::FIELD; } - case ir::AstNodeType::MEMBER_EXPRESSION: { - return {node, pg, false, ReferenceKind::MEMBER, {}}; + case ir::AstNodeType::CLASS_DEFINITION: { + auto *classDef = declNode->AsClassDefinition(); + return classDef->IsStatic() ? ReferenceKind::STATIC_CLASS : ReferenceKind::CLASS; } - case ir::AstNodeType::VARIABLE_DECLARATION: { - ASSERT(node->AsVariableDeclaration()->Declarators().size() == 1); - return LReference::CreateLRef(pg, node->AsVariableDeclaration()->Declarators()[0]->Id(), true); + case ir::AstNodeType::METHOD_DEFINITION: { + return ReferenceKind::METHOD; } - case ir::AstNodeType::VARIABLE_DECLARATOR: { - return LReference::CreateLRef(pg, node->AsVariableDeclarator()->Id(), true); + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { } - case ir::AstNodeType::ARRAY_PATTERN: - case ir::AstNodeType::OBJECT_PATTERN: { - return {node, pg, isDeclaration, ReferenceKind::DESTRUCTURING, {}}; + default: { + break; } - case ir::AstNodeType::ASSIGNMENT_PATTERN: { - return LReference::CreateLRef(pg, node->AsAssignmentPattern()->Left(), true); + } + + return ReferenceKind::LOCAL; +} + +void STSLReference::GetValue() const +{ + switch (refKind_) { + case ReferenceKind::MEMBER: { + node_->AsMemberExpression()->Compile(stsg_); + break; } - case ir::AstNodeType::REST_ELEMENT: { - return LReference::CreateLRef(pg, node->AsRestElement()->Argument(), true); + default: { + stsg_->LoadVar(node_->AsIdentifier(), res_); + break; + } + } +} + +void STSLReference::SetValue() const +{ + switch (refKind_) { + case ReferenceKind::MEMBER: { + auto *memberExpr = node_->AsMemberExpression(); + stsg_->ApplyWidening(node_, memberExpr->TsType()); + + if (memberExpr->IsComputed()) { + stsg_->StoreArrayElement(node_, baseReg_, propReg_); + break; + } + + auto &propName = memberExpr->Property()->AsIdentifier()->Name(); + if (memberExpr->PropVar()->HasFlag(binder::VariableFlags::STATIC)) { + util::StringView fullName = stsg_->FormClassPropReference(staticObjRef_->AsSTSObjectType(), propName); + stsg_->StoreStaticProperty(node_, memberExpr->TsType(), fullName); + break; + } + + stsg_->StoreProperty(node_, memberExpr->TsType(), baseReg_, propName); + break; } default: { - UNREACHABLE(); + stsg_->StoreVar(node_->AsIdentifier(), res_); + break; } } } + } // namespace panda::es2panda::compiler diff --git a/compiler/base/lreference.h b/compiler/base/lreference.h index 0df234059..1924781d6 100644 --- a/compiler/base/lreference.h +++ b/compiler/base/lreference.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_BASE_LREFERENCE_H -#define ES2PANDA_COMPILER_BASE_LREFERENCE_H +#ifndef ES2PANDA_COMPILER_BASE_JSLREFERENCE_H +#define ES2PANDA_COMPILER_BASE_JSLREFERENCE_H #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/ir/irnode.h" @@ -23,6 +23,10 @@ namespace panda::es2panda::ir { class AstNode; } // namespace panda::es2panda::ir +namespace panda::es2panda::checker { +class STSObjectType; +} // namespace panda::es2panda::checker + namespace panda::es2panda::compiler { enum class ReferenceKind { MEMBER, @@ -30,34 +34,96 @@ enum class ReferenceKind { SUPER, VAR_OR_GLOBAL, DESTRUCTURING, + LOCAL, + STATIC_FIELD, + FIELD, + CLASS, + STATIC_CLASS, + METHOD, + STATIC_METHOD, }; +class CodeGen; +class STSGen; class PandaGen; class LReference { public: - LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind, - binder::ScopeFindResult res); ~LReference() = default; NO_COPY_SEMANTIC(LReference); - NO_MOVE_SEMANTIC(LReference); + DEFAULT_MOVE_SEMANTIC(LReference); - void GetValue(); - void SetValue(); - binder::Variable *Variable() const; - ReferenceKind Kind() const; + ReferenceKind Kind() const + { + return refKind_; + } - static LReference CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration); + binder::Variable *Variable() const + { + return res_.variable; + } + +protected: + using LReferenceBase = std::tuple; + static LReferenceBase CreateBase(CodeGen *cg, const ir::AstNode *node, bool isDeclaration); + + explicit LReference(const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, bool isDeclaration) + : node_(node), refKind_(refKind), res_(res), isDeclaration_(isDeclaration) + { + } -private: const ir::AstNode *node_; - PandaGen *pg_; ReferenceKind refKind_; binder::ScopeFindResult res_; + bool isDeclaration_; +}; + +class JSLReference : public LReference { +public: + JSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration); + ~JSLReference() = default; + NO_COPY_SEMANTIC(JSLReference); + NO_MOVE_SEMANTIC(JSLReference); + + void GetValue() const; + void SetValue() const; + + static JSLReference Create(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) + { + return std::make_from_tuple(CreateBase(cg, node, isDeclaration)); + } + +private: + PandaGen *pg_; VReg obj_; VReg privateCtor_ {}; Operand prop_; - bool isDeclaration_; +}; + +class STSLReference : public LReference { +public: + STSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration); + ~STSLReference() = default; + NO_COPY_SEMANTIC(STSLReference); + NO_MOVE_SEMANTIC(STSLReference); + + void GetValue() const; + void SetValue() const; + + static STSLReference Create(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) + { + return std::make_from_tuple(CreateBase(cg, node, isDeclaration)); + } + + static ReferenceKind ResolveReferenceKind(const binder::Variable *variable); + +private: + STSGen *stsg_; + const checker::Type *staticObjRef_ {}; + VReg baseReg_ {}; + VReg propReg_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/base/optionalChain.cpp b/compiler/base/optionalChain.cpp index c9cec7519..e115517dd 100644 --- a/compiler/base/optionalChain.cpp +++ b/compiler/base/optionalChain.cpp @@ -40,7 +40,7 @@ void OptionalChain::Check(compiler::VReg obj) RegScope rs(pg_); - if (obj == INVALID_VREG) { + if (obj.IsInvalid()) { obj = pg_->AllocReg(); pg_->StoreAccumulator(node_, obj); } diff --git a/compiler/core/JSemitter.cpp b/compiler/core/JSemitter.cpp new file mode 100644 index 000000000..2a0010fe3 --- /dev/null +++ b/compiler/core/JSemitter.cpp @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "JSemitter.h" + +#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "assembly-program.h" + +namespace panda::es2panda::compiler { +pandasm::Function *JSFunctionEmitter::GenFunctionSignature() +{ + auto *func = new pandasm::Function(cg_->InternalName().Mutf8(), panda_file::SourceLang::ECMASCRIPT); + programElement_->func = func; + + size_t paramCount = cg_->InternalParamCount(); + func->params.reserve(paramCount); + + for (uint32_t i = 0; i < paramCount; ++i) { + func->params.emplace_back(pandasm::Type("any", 0), panda_file::SourceLang::ECMASCRIPT); + } + + func->regs_num = VReg::REG_START - cg_->TotalRegsNum(); + func->return_type = pandasm::Type("any", 0); + + return func; +} + +void JSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + [[maybe_unused]] binder::LocalVariable *variable) const +{ + variableDebug.signature = "any"; + variableDebug.signature_type = "any"; +} + +void JSFunctionEmitter::GenFunctionAnnotations(pandasm::Function *func) +{ + pandasm::AnnotationData funcAnnotationData("_ESAnnotation"); + pandasm::AnnotationElement icSizeAnnotationElement( + "icSize", std::make_unique( + pandasm::ScalarValue::Create(Pg()->IcSize()))); + funcAnnotationData.AddElement(std::move(icSizeAnnotationElement)); + + pandasm::AnnotationElement parameterLengthAnnotationElement( + "parameterLength", std::make_unique( + pandasm::ScalarValue::Create(Pg()->FormalParametersCount()))); + funcAnnotationData.AddElement(std::move(parameterLengthAnnotationElement)); + + pandasm::AnnotationElement funcNameAnnotationElement( + "funcName", std::make_unique( + pandasm::ScalarValue::Create(Pg()->FunctionName().Mutf8()))); + funcAnnotationData.AddElement(std::move(funcNameAnnotationElement)); + + func->metadata->AddAnnotations({funcAnnotationData}); +} + +void JSEmitter::GenAnnotation() +{ + prog_->lang = panda_file::SourceLang::ECMASCRIPT; + GenESAnnoatationRecord(); + GenESModuleModeRecord(context_->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); +} + +void JSEmitter::GenESAnnoatationRecord() +{ + auto annotationRecord = pandasm::Record("_ESAnnotation", prog_->lang); + annotationRecord.metadata->SetAttribute("external"); + annotationRecord.metadata->SetAccessFlags(ACC_ANNOTATION); + prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); +} + +void JSEmitter::GenESModuleModeRecord(bool isModule) +{ + auto modeRecord = pandasm::Record("_ESModuleMode", prog_->lang); + modeRecord.metadata->SetAccessFlags(ACC_PUBLIC); + + auto modeField = pandasm::Field(prog_->lang); + modeField.name = "isModule"; + modeField.type = pandasm::Type("u8", 0); + modeField.metadata->SetValue( + pandasm::ScalarValue::Create(static_cast(isModule))); + + modeRecord.field_list.emplace_back(std::move(modeField)); + + prog_->record_table.emplace(modeRecord.name, std::move(modeRecord)); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/JSemitter.h b/compiler/core/JSemitter.h new file mode 100644 index 000000000..9db408561 --- /dev/null +++ b/compiler/core/JSemitter.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_JS_EMITTER_H +#define ES2PANDA_COMPILER_CORE_JS_EMITTER_H + +#include "emitter.h" + +namespace panda::es2panda::compiler { + +class JSFunctionEmitter : public FunctionEmitter { +public: + JSFunctionEmitter(const CodeGen *cg, ProgramElement *programElement) : FunctionEmitter(cg, programElement) {} + ~JSFunctionEmitter() = default; + NO_COPY_SEMANTIC(JSFunctionEmitter); + NO_MOVE_SEMANTIC(JSFunctionEmitter); + +protected: + const PandaGen *Pg() const + { + return reinterpret_cast(cg_); + } + + pandasm::Function *GenFunctionSignature() override; + + void GenFunctionAnnotations(pandasm::Function *func) override; + void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const override; +}; + +class JSEmitter : public Emitter { +public: + explicit JSEmitter(const CompilerContext *context) : Emitter(context) {} + virtual ~JSEmitter() = default; + NO_COPY_SEMANTIC(JSEmitter); + NO_MOVE_SEMANTIC(JSEmitter); + + void GenAnnotation() override; + +private: + void GenESAnnoatationRecord(); + void GenESModuleModeRecord(bool isModule); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/STSGen.cpp b/compiler/core/STSGen.cpp new file mode 100644 index 000000000..eaa8d1ac6 --- /dev/null +++ b/compiler/core/STSGen.cpp @@ -0,0 +1,1191 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "STSGen.h" + +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/statement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/binaryExpression.h" +#include "plugins/ecmascript/es2panda/ir/statements/deferStatement.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/compiler/base/lreference.h" +#include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/compiler/core/dynamicContext.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::compiler { + +void STSGen::InitializeContainingClass() +{ + auto *containingClass = util::Helpers::GetContainingClassDefinition(rootNode_); + + if (containingClass) { + containingClassType_ = containingClass->TsType()->AsSTSObjectType(); + return; + } + + auto *containingInterface = util::Helpers::GetContainingInterfaceDeclaration(rootNode_); + containingClassType_ = containingInterface->TsType()->AsSTSObjectType(); +} + +const checker::STSChecker *STSGen::Checker() const +{ + return context_->Checker()->AsSTSChecker(); +} + +const checker::Type *STSGen::ReturnType() const +{ + return rootNode_->AsScriptFunction()->Signature()->ReturnType(); +} + +void STSGen::ApplyWidenAndStoreAccumulator(const ir::AstNode *node, VReg &vreg, const checker::Type *targetType) +{ + ApplyWidening(node, targetType); + StoreAccumulator(node, vreg); +} + +VReg STSGen::StoreException(const ir::AstNode *node) +{ + VReg exception = AllocReg(); + ra_.Emit(node, exception); + + acc_.SetType(Checker()->GlobalBuiltinExceptionType()); + exception.SetType(acc_.GetType()); + return exception; +} + +void STSGen::StoreAccumulator(const ir::AstNode *node, VReg &vreg) +{ + if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::STS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, vreg); + } else if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::STS_WIDE_NUMERIC)) { + ra_.Emit(node, vreg); + } else { + ra_.Emit(node, vreg); + } + + vreg.SetType(acc_.GetType()); +} + +void STSGen::LoadAccumulator(const ir::AstNode *node, VReg vreg) +{ + if (vreg.GetType()->HasTypeFlag(checker::TypeFlag::STS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, vreg); + } else if (vreg.GetType()->HasTypeFlag(checker::TypeFlag::STS_WIDE_NUMERIC)) { + ra_.Emit(node, vreg); + } else { + ra_.Emit(node, vreg); + } + + acc_.SetType(vreg.GetType()); +} + +void STSGen::MoveVreg(const ir::AstNode *node, VReg &vd, VReg vs) +{ + if (vs.GetType()->HasTypeFlag(checker::TypeFlag::STS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, vd, vs); + } else if (vs.GetType()->HasTypeFlag(checker::TypeFlag::STS_WIDE_NUMERIC)) { + ra_.Emit(node, vd, vs); + } else { + ra_.Emit(node, vd, vs); + } + + vd.SetType(vs.GetType()); +} + +void STSGen::LoadVar(const ir::AstNode *node, const binder::ScopeFindResult &result) +{ + auto *local = result.variable->AsLocalVariable(); + + switch (STSLReference::ResolveReferenceKind(result.variable)) { + case ReferenceKind::STATIC_FIELD: { + auto fullName = FormClassPropReference(result); + LoadStaticProperty(node, result.variable->TsType(), fullName); + break; + } + case ReferenceKind::FIELD: { + LoadProperty(node, result.variable->TsType(), GetThisReg(), result.name); + break; + } + case ReferenceKind::METHOD: + case ReferenceKind::STATIC_METHOD: + case ReferenceKind::CLASS: + case ReferenceKind::STATIC_CLASS: { + acc_.SetType(result.variable->TsType()); + break; + } + case ReferenceKind::LOCAL: { + LoadAccumulator(node, local->Vreg()); + break; + } + default: { + UNREACHABLE(); + } + } + + if (targetType_) { + ApplyWidening(node, targetType_); + } +} + +void STSGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result) +{ + auto *local = result.variable->AsLocalVariable(); + ApplyWidening(node, local->TsType()); + + switch (STSLReference::ResolveReferenceKind(result.variable)) { + case ReferenceKind::STATIC_FIELD: { + auto fullName = FormClassPropReference(result); + StoreStaticProperty(node, result.variable->TsType(), fullName); + break; + } + case ReferenceKind::FIELD: { + StoreProperty(node, result.variable->TsType(), GetThisReg(), result.name); + break; + } + case ReferenceKind::LOCAL: { + StoreAccumulator(node, local->Vreg()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +util::StringView STSGen::FormClassPropReference(const checker::STSObjectType *classType, const util::StringView &name) +{ + std::stringstream ss; + ss << classType->AssemblerName() << '.' << name; + auto res = programElement_->strings.insert(ss.str()); + + return util::StringView(*res.first); +} + +util::StringView STSGen::FormClassPropReference(const binder::ScopeFindResult &result) +{ + auto containingClass = util::Helpers::GetContainingClassDefinition(result.variable->Declaration()->Node()); + auto containingClassType = containingClass->TsType()->AsSTSObjectType(); + return FormClassPropReference(containingClassType, result.name); +} + +void STSGen::StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(containingClassType_, name); + StoreStaticProperty(node, propType, fullName); +} + +void STSGen::StoreStaticProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &fullName) +{ + if (propType->HasTypeFlag(checker::TypeFlag::STS_ARRAY_OR_OBJECT)) { + sa_.Emit(node, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::STS_WIDE_NUMERIC)) { + sa_.Emit(node, fullName); + } else { + sa_.Emit(node, fullName); + } +} + +void STSGen::LoadStaticProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &fullName) +{ + if (propType->HasTypeFlag(checker::TypeFlag::STS_ARRAY_OR_OBJECT)) { + sa_.Emit(node, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::STS_WIDE_NUMERIC)) { + sa_.Emit(node, fullName); + } else { + sa_.Emit(node, fullName); + } + + acc_.SetType(propType); +} + +void STSGen::StoreProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(objReg.GetType()->AsSTSObjectType(), name); + + if (propType->HasTypeFlag(checker::TypeFlag::STS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, objReg, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::STS_WIDE_NUMERIC)) { + ra_.Emit(node, objReg, fullName); + } else { + ra_.Emit(node, objReg, fullName); + } +} + +void STSGen::LoadProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(objReg.GetType()->AsSTSObjectType(), name); + + if (propType->HasTypeFlag(checker::TypeFlag::STS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, objReg, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::STS_WIDE_NUMERIC)) { + ra_.Emit(node, objReg, fullName); + } else { + ra_.Emit(node, objReg, fullName); + } + + acc_.SetType(propType); +} + +void STSGen::LoadThis(const ir::AstNode *node) +{ + binder::ScopeFindResult res = scope_->Find(binder::Binder::MANDATORY_PARAM_THIS); + LoadVar(node, res); +} + +VReg &STSGen::GetThisReg() +{ + binder::ScopeFindResult res = scope_->Find(binder::Binder::MANDATORY_PARAM_THIS); + return res.variable->AsLocalVariable()->Vreg(); +} + +void STSGen::LoadDefaultValue([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const checker::Type *type) +{ + if (type->IsSTSObjectType() || type->IsSTSArrayType()) { + LoadAccumulatorNull(node, type); + } else { + auto ttctx = TargetTypeContext(this, type); + LoadAccumulatorInt(node, 0); + } +} + +void STSGen::EmitReturnVoid(const ir::AstNode *node) +{ + sa_.Emit(node); +} + +void STSGen::ReturnAcc(const ir::AstNode *node) +{ + if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::STS_ARRAY_OR_OBJECT)) { + sa_.Emit(node); + } else if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::STS_WIDE_NUMERIC)) { + sa_.Emit(node); + } else { + sa_.Emit(node); + } +} + +bool STSGen::TryLoadConstantExpression(const ir::Expression *node) +{ + const auto *type = node->TsType(); + + if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return false; + } + + auto typeKind = checker::STSChecker::TypeKind(type); + + switch (typeKind) { + case checker::TypeFlag::CHAR: { + LoadAccumulatorChar(node, type->AsCharType()->GetValue()); + break; + } + case checker::TypeFlag::STS_BOOLEAN: { + LoadAccumulatorBoolean(node, type->AsSTSBooleanType()->GetValue()); + break; + } + case checker::TypeFlag::BYTE: { + LoadAccumulatorByte(node, type->AsByteType()->GetValue()); + break; + } + case checker::TypeFlag::SHORT: { + LoadAccumulatorShort(node, type->AsShortType()->GetValue()); + break; + } + case checker::TypeFlag::INT: { + LoadAccumulatorInt(node, type->AsIntType()->GetValue()); + break; + } + case checker::TypeFlag::LONG: { + LoadAccumulatorWideInt(node, type->AsLongType()->GetValue()); + break; + } + case checker::TypeFlag::FLOAT: { + LoadAccumulatorFloat(node, type->AsFloatType()->GetValue()); + break; + } + case checker::TypeFlag::DOUBLE: { + LoadAccumulatorDouble(node, type->AsDoubleType()->GetValue()); + break; + } + case checker::TypeFlag::STS_OBJECT: { + LoadAccumulatorString(node, type->AsSTSObjectType()->AsSTSStringType()->GetValue()); + break; + } + default: { + UNREACHABLE(); + } + } + + return true; +} + +void STSGen::ApplyWidening(const ir::AstNode *node, const checker::Type *targetType) +{ + auto ttctx = TargetTypeContext(this, targetType); + + auto typeKind = checker::STSChecker::TypeKind(targetType); + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + CastToDouble(node); + break; + } + case checker::TypeFlag::FLOAT: { + CastToFloat(node); + break; + } + case checker::TypeFlag::LONG: { + CastToLong(node); + break; + } + default: { + break; + } + } +} + +void STSGen::SwapBinaryOpArgs(const ir::AstNode *node, VReg &lhs) +{ + RegScope rs(this); + auto tmp = AllocReg(); + + StoreAccumulator(node, tmp); + LoadAccumulator(node, lhs); + MoveVreg(node, lhs, tmp); +} + +void STSGen::CastToBoolean([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalSTSBooleanType()); +} + +void STSGen::CastToByte([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: { + return; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalByteType()); +} + +void STSGen::CastToChar([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalCharType()); +} + +void STSGen::CastToShort([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + return; + } + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalShortType()); +} + +void STSGen::CastToDouble(const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + return; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalDoubleType()); +} + +void STSGen::CastToFloat(const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + return; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalFloatType()); +} + +void STSGen::CastToLong(const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::LONG: { + return; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalLongType()); +} + +void STSGen::CastToInt(const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalIntType()); +} + +void STSGen::ToBinaryResult(const ir::AstNode *node, Label *ifFalse) +{ + Label *end = AllocLabel(); + sa_.Emit(node, 1); + sa_.Emit(node, end); + SetLabel(node, ifFalse); + sa_.Emit(node, 0); + SetLabel(node, end); +} + +void STSGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs) +{ + ApplyWidening(node, targetType_); + + switch (op) { + case lexer::TokenType::PUNCTUATOR_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryEquality(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryEquality(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + SwapBinaryOpArgs(node, lhs); + IsInstance(node, lhs.GetType()->AsSTSObjectType()->AssemblerName()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void STSGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse) +{ + ApplyWidening(node, targetType_); + + switch (op) { + case lexer::TokenType::PUNCTUATOR_EQUAL: { + BinaryEqualityCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + BinaryEqualityCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + SwapBinaryOpArgs(node, lhs); + sa_.Emit(node, lhs.GetType()->AsSTSObjectType()->AssemblerName()); + BranchIfFalse(node, ifFalse); + acc_.SetType(Checker()->GlobalSTSBooleanType()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void STSGen::EmitNullPointerException(const ir::AstNode *node) +{ + VReg exception = StoreException(node); + NewObject(node, exception, Signatures::BUILTIN_NULLPOINTER_EXCEPTION); + CallThisStatic0(node, exception, Signatures::BUILTIN_NULLPOINTER_EXCEPTION_CTOR); + EmitThrow(node, exception); +} + +void STSGen::CompileStatements(const ArenaVector &statements) +{ + for (const auto *stmt : statements) { + stmt->Compile(this); + } +} + +void STSGen::CompileDeferStatements(const ArenaVector &statements) +{ + for (auto it = statements.crbegin(); it != statements.crend(); it++) { + auto *stmt = *it; + if (!stmt->IsDeferStatement()) { + continue; + } + stmt->AsDeferStatement()->Stmt()->Compile(this); + } +} + +void STSGen::CompileStatementList(const ArenaVector &statements) +{ + if (!scope_->HasFlag(binder::ScopeFlags::DEFER_STMT)) { + CompileStatements(statements); + return; + } + + ASSERT(!statements.empty()); + auto *node = statements.front(); + + TrapContext trapCtx(this); + const auto &labelSet = trapCtx.LabelSet(); + + SetLabel(node, labelSet.TryBegin()); + CompileStatements(statements); + CompileDeferStatements(statements); + SetLabel(node, labelSet.TryEnd()); + Branch(node, labelSet.CatchEnd()); + + SetLabel(node, labelSet.CatchBegin()); + VReg exception = StoreException(node); + CompileDeferStatements(statements); + EmitThrow(node, exception); + SetLabel(node, labelSet.CatchEnd()); +} + +void STSGen::Negate(const ir::AstNode *node) +{ + auto typeKind = checker::STSChecker::TypeKind(acc_.GetType()); + + switch (typeKind) { + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void STSGen::LogicalNot(const ir::AstNode *node) +{ + ASSERT(acc_.GetType()->IsSTSBooleanType()); + sa_.Emit(node); + sa_.Emit(node, 1); +} + +void STSGen::Unary(const ir::AstNode *node, lexer::TokenType op) +{ + switch (op) { + case lexer::TokenType::PUNCTUATOR_PLUS: { + break; // NOP -> Unary numeric promotion is performed + } + case lexer::TokenType::PUNCTUATOR_MINUS: { + UnaryMinus(node); + break; + } + case lexer::TokenType::PUNCTUATOR_TILDE: { + UnaryTilde(node); + break; + } + case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { + LogicalNot(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void STSGen::UnaryMinus(const ir::AstNode *node) +{ + switch (checker::STSChecker::STSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::BYTE: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void STSGen::UnaryTilde(const ir::AstNode *node) +{ + switch (checker::STSChecker::STSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::BYTE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void STSGen::Update(const ir::AstNode *node, lexer::TokenType op) +{ + switch (op) { + case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: { + UpdateOperator(node); + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: { + UpdateOperator(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void STSGen::StringBuilderAppend(const ir::AstNode *node, VReg builder) +{ + RegScope rs(this); + util::StringView signature {}; + + node->Compile(this); + + switch (checker::STSChecker::STSType(acc_.GetType())) { + case checker::TypeFlag::STS_BOOLEAN: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_BOOLEAN; + break; + } + case checker::TypeFlag::CHAR: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_CHAR; + break; + } + case checker::TypeFlag::SHORT: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::INT: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_INT; + break; + } + case checker::TypeFlag::LONG: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_LONG; + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + [[fallthrough]]; + } + case checker::TypeFlag::DOUBLE: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_DOUBLE; + break; + } + default: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_BUILTIN_STRING; + break; + } + } + + if (acc_.GetType()->IsSTSObjectType() && !acc_.GetType()->IsSTSStringType()) { + ra_.Emit(node, Signatures::BUILTIN_OBJECT_TO_STRING, VReg::RegStart(), 0); + } + + VReg arg0 = AllocReg(); + StoreAccumulator(node, arg0); + + CallThisStatic1(node, builder, signature, arg0); +} + +void STSGen::AppendString(const ir::BinaryExpression *binExpr, VReg &builder) +{ + ASSERT(binExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS); + + auto *left = binExpr->Left(); + auto *right = binExpr->Right(); + + if (left->IsBinaryExpression()) { + AppendString(left->AsBinaryExpression(), builder); + } else { + StringBuilderAppend(left, builder); + } + + StringBuilderAppend(right, builder); +} + +void STSGen::BuildString(const ir::AstNode *node) +{ + auto *binExpr = node->AsBinaryExpression(); + RegScope rs(this); + VReg builder = AllocReg(); + + sa_.Emit(node, Signatures::BUILTIN_STRING_BUILDER_CTOR, VReg::RegStart(), VReg::RegStart()); + StoreAccumulator(node, builder); + + AppendString(binExpr, builder); + CallThisStatic0(node, builder, Signatures::BUILTIN_STRING_BUILDER_TO_STRING); +} + +void STSGen::NewObject(const ir::AstNode *node, VReg &ctor, util::StringView name) +{ + ra_.Emit(node, ctor, name); +} + +void STSGen::NewArray(const ir::AstNode *node, VReg &arr, VReg dim, const checker::Type *arrType) +{ + std::stringstream ss; + arrType->ToAssemblerType(ss); + auto res = programElement_->strings.insert(ss.str()); + + ra_.Emit(node, arr, dim, util::StringView(*res.first)); +} + +void STSGen::LoadArrayLength(const ir::AstNode *node, VReg arrayReg) +{ + ra_.Emit(node, arrayReg); + acc_.SetType(arrayReg.GetType()); +} + +void STSGen::LoadArrayElement(const ir::AstNode *node, VReg objectReg) +{ + auto *elementType = objectReg.GetType()->AsSTSArrayType()->ElementType(); + + switch (checker::STSChecker::STSType(elementType)) { + case checker::TypeFlag::BYTE: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::INT: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::LONG: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::FLOAT: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::DOUBLE: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::STS_ARRAY: + case checker::TypeFlag::STS_OBJECT: { + ra_.Emit(node, objectReg); + break; + } + + default: { + UNREACHABLE(); + } + } + + acc_.SetType(elementType); +} + +void STSGen::StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index) +{ + auto *elementType = objectReg.GetType()->AsSTSArrayType()->ElementType(); + + switch (checker::STSChecker::STSType(elementType)) { + case checker::TypeFlag::BYTE: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::INT: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::LONG: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::FLOAT: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::DOUBLE: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::STS_ARRAY: + case checker::TypeFlag::STS_OBJECT: { + ra_.Emit(node, objectReg, index); + break; + } + + default: { + UNREACHABLE(); + } + } + + acc_.SetType(elementType); +} + +void STSGen::ThrowException(const ir::Expression *expr) +{ + RegScope rs(this); + + expr->Compile(this); + VReg arg = AllocReg(); + StoreAccumulator(expr, arg); + EmitThrow(expr, arg); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/STSGen.h b/compiler/core/STSGen.h new file mode 100644 index 000000000..eb8dc9411 --- /dev/null +++ b/compiler/core/STSGen.h @@ -0,0 +1,637 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_STSGEN_H +#define ES2PANDA_COMPILER_CORE_STSGEN_H + +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/STSfunction.h" +#include "plugins/ecmascript/es2panda/compiler/core/targetTypeContext.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::compiler { + +class STSGen : public CodeGen { +public: + explicit STSGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : CodeGen(allocator, spiller, context, scope, programElement) + { + InitializeContainingClass(); + STSFunction::Compile(this); + } + + const checker::STSChecker *Checker() const; + const checker::Type *ReturnType() const; + + const checker::STSObjectType *ContainingClassType() const + { + return containingClassType_; + } + + VReg &Acc() + { + return acc_; + } + + const VReg &Acc() const + { + return acc_; + } + + VReg StoreException(const ir::AstNode *node); + void ApplyWidenAndStoreAccumulator(const ir::AstNode *node, VReg &vreg, const checker::Type *targetType); + void StoreAccumulator(const ir::AstNode *node, VReg &vreg); + void LoadAccumulator(const ir::AstNode *node, VReg vreg); + void MoveVreg(const ir::AstNode *node, VReg &vd, VReg vs); + + void LoadVar(const ir::AstNode *node, const binder::ScopeFindResult &result); + void StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result); + + void LoadStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); + void StoreStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); + + void StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &name); + util::StringView FormClassPropReference(const checker::STSObjectType *classType, const util::StringView &name); + + void StoreProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name); + void LoadProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name); + + void LoadThis(const ir::AstNode *node); + VReg &GetThisReg(); + + void LoadDefaultValue(const ir::AstNode *node, const checker::Type *type); + void EmitReturnVoid(const ir::AstNode *node); + void ReturnAcc(const ir::AstNode *node); + + void IsInstance(const ir::AstNode *node, util::StringView name) + { + sa_.Emit(node, name); + acc_.SetType(Checker()->GlobalSTSBooleanType()); + } + + void Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs); + void Unary(const ir::AstNode *node, lexer::TokenType op); + void Update(const ir::AstNode *node, lexer::TokenType op); + + bool TryLoadConstantExpression(const ir::Expression *node); + void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse); + + void BranchIfFalse(const ir::AstNode *node, Label *ifFalse) + { + sa_.Emit(node, ifFalse); + } + + void BranchIfTrue(const ir::AstNode *node, Label *ifFalse) + { + sa_.Emit(node, ifFalse); + } + + void EmitThrow(const ir::AstNode *node, VReg err) + { + ra_.Emit(node, err); + } + + void EmitNullPointerException(const ir::AstNode *node); + + void ThrowException(const ir::Expression *expr); + + void Negate(const ir::AstNode *node); + void LogicalNot(const ir::AstNode *node); + + void LoadAccumulatorByte(const ir::AstNode *node, int8_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::BYTE); + } + + void LoadAccumulatorShort(const ir::AstNode *node, int16_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::SHORT); + } + + void LoadAccumulatorInt(const ir::AstNode *node, int32_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::INT); + } + + void LoadAccumulatorWideInt(const ir::AstNode *node, int64_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::LONG); + } + + void LoadAccumulatorFloat(const ir::AstNode *node, float number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::FLOAT); + } + + void LoadAccumulatorDouble(const ir::AstNode *node, double number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::DOUBLE); + } + + void LoadAccumulatorBoolean(const ir::AstNode *node, bool value) + { + sa_.Emit(node, value ? 1 : 0); + acc_.SetType(Checker()->GlobalSTSBooleanType()); + } + + void LoadAccumulatorString(const ir::AstNode *node, util::StringView str) + { + sa_.Emit(node, str); + acc_.SetType(Checker()->GlobalSTSStringType()); + } + + void LoadAccumulatorNull(const ir::AstNode *node, const checker::Type *type) + { + sa_.Emit(node); + acc_.SetType(type); + } + + void LoadAccumulatorChar(const ir::AstNode *node, char16_t value) + { + sa_.Emit(node, value); + acc_.SetType(Checker()->GlobalCharType()); + } + + void ApplyWidening(const ir::AstNode *node) + { + if (targetType_) { + ApplyWidening(node, targetType_); + } + } + void ApplyWidening(const ir::AstNode *node, const checker::Type *targetType); + void SwapBinaryOpArgs(const ir::AstNode *node, VReg &lhs); + + void LoadArrayLength(const ir::AstNode *node, VReg arrayReg); + void LoadArrayElement(const ir::AstNode *node, VReg objReg); + void StoreArrayElement(const ir::AstNode *node, VReg objReg, VReg index); + + void CompileStatementList(const ArenaVector &statements); + + // Cast + void CastToBoolean(const ir::AstNode *node); + void CastToByte(const ir::AstNode *node); + void CastToChar(const ir::AstNode *node); + void CastToShort(const ir::AstNode *node); + void CastToDouble(const ir::AstNode *node); + void CastToFloat(const ir::AstNode *node); + void CastToLong(const ir::AstNode *node); + void CastToInt(const ir::AstNode *node); + + // Call, Construct + void NewArray(const ir::AstNode *node, VReg &arr, VReg dim, const checker::Type *arrType); + void NewObject(const ir::AstNode *node, VReg &ctor, util::StringView name); + void BuildString(const ir::AstNode *node); + void InitObject(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + CallImpl(node, signature, arguments); + } + + void CallStatic(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + CallImpl(node, signature, arguments); + } + + void CallThisStatic(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + CallThisImpl(node, ctor, signature, arguments); + } + + void CallThisVirtual(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + CallThisImpl(node, ctor, signature, arguments); + } + + void CallThisStatic0(const ir::AstNode *node, VReg &ctor, util::StringView name) + { + ra_.Emit(node, name, ctor, VReg::RegStart()); + } + + void CallThisStatic1(const ir::AstNode *node, VReg &ctor, util::StringView name, VReg &arg0) + { + ra_.Emit(node, name, ctor, arg0); + } + + void CallThisStatic2(const ir::AstNode *node, VReg &ctor, util::StringView name, VReg &arg0, VReg &arg1) + { + ra_.Emit(node, name, ctor, arg0, arg1, VReg::RegStart()); + } + + void GetType(const ir::AstNode *node) + { + auto classRef = acc_.GetType()->AsSTSObjectType()->AssemblerName(); + sa_.Emit(node, classRef); + } + + ~STSGen() = default; + NO_COPY_SEMANTIC(STSGen); + NO_MOVE_SEMANTIC(STSGen); + +private: + void StringBuilderAppend(const ir::AstNode *node, VReg builder); + void AppendString(const ir::BinaryExpression *binExpr, VReg &builder); + void CompileStatements(const ArenaVector &statements); + void CompileDeferStatements(const ArenaVector &statements); + util::StringView FormClassPropReference(const binder::ScopeFindResult &result); + void UnaryMinus(const ir::AstNode *node); + void UnaryTilde(const ir::AstNode *node); + + template + void StoreValueIntoArray(const ir::AstNode *node, VReg &arr, VReg &index) + { + ra_.Emit(node, arr, index); + } + + template + void UpdateOperator(const ir::AstNode *node) + { + switch (checker::STSChecker::STSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + RegScope scope(this); + VReg reg = AllocReg(); + ra_.Emit(node, reg, 1LL); + ra_.Emit(node, reg); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::BYTE: { + sa_.Emit(node, 1); + break; + } + case checker::TypeFlag::DOUBLE: { + RegScope scope(this); + VReg reg = AllocReg(); + ra_.Emit(node, reg, 1.0); + ra_.Emit(node, reg); + break; + } + case checker::TypeFlag::FLOAT: { + RegScope scope(this); + VReg reg = AllocReg(); + ra_.Emit(node, reg, 1.0F); + ra_.Emit(node, reg); + break; + } + default: { + UNREACHABLE(); + } + } + } + + template + void BinaryEqualityObj(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + ra_.Emit(node, lhs, ifFalse); + } + + template + void BinaryNumberComparison(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + ra_.Emit(node, lhs); + sa_.Emit(node, ifFalse); + } + + template + void BinaryEquality(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + BinaryEqualityCondition(node, lhs, ifFalse); + ToBinaryResult(node, ifFalse); + acc_.SetType(Checker()->GlobalSTSBooleanType()); + } + + template + void BinaryEqualityCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + auto typeKind = checker::STSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::STS_OBJECT: { + ASSERT(lhs.GetType()->IsSTSObjectType()); + if (lhs.GetType()->IsSTSStringType()) { + RegScope rs(this); + VReg arg0 = AllocReg(); + StoreAccumulator(node, arg0); + CallThisStatic1(node, lhs, Signatures::BUILTIN_STRING_EQUALS, arg0); + acc_.SetType(Checker()->GlobalSTSBooleanType()); + if constexpr (std::is_same_v) { + LogicalNot(node); + } + BranchIfFalse(node, ifFalse); + return; + } + + BinaryEqualityObj(node, lhs, ifFalse); + + break; + } + case checker::TypeFlag::DOUBLE: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::FLOAT: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::LONG: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + ra_.Emit(node, lhs, ifFalse); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalSTSBooleanType()); + } + + template + void BinaryRelation(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + BinaryRelationCondition(node, lhs, ifFalse); + ToBinaryResult(node, ifFalse); + acc_.SetType(Checker()->GlobalSTSBooleanType()); + } + + template + void BinaryRelationCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + auto typeKind = checker::STSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::FLOAT: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::LONG: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::STS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + ra_.Emit(node, lhs, ifFalse); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalSTSBooleanType()); + } + + template + void BinaryArithmetic(const ir::AstNode *node, VReg lhs) + { + auto typeKind = checker::STSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalDoubleType()); + break; + } + case checker::TypeFlag::FLOAT: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalFloatType()); + break; + } + default: { + BinaryBitwiseArithmetic(node, lhs); + } + } + } + + template + void BinaryBitwiseArithmetic(const ir::AstNode *node, VReg lhs) + { + auto typeKind = checker::STSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::LONG: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalLongType()); + break; + } + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalIntType()); + break; + } + case checker::TypeFlag::STS_BOOLEAN: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalSTSBooleanType()); + break; + } + default: { + UNREACHABLE(); + } + } + } + +#define COMPILE_ARG(idx) \ + ASSERT(idx < arguments.size()); \ + auto *paramType##idx = signature->Params()[idx]->TsType(); \ + auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ + arguments[idx]->Compile(this); \ + VReg arg##idx = AllocReg(); \ + ApplyWidenAndStoreAccumulator(node, arg##idx, paramType##idx) + + template + void CallThisImpl(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + RegScope rs(this); + util::StringView name = signature->InternalName(); + + switch (arguments.size()) { + case 0: { + ra_.Emit(node, name, ctor, VReg::RegStart()); + break; + } + case 1: { + COMPILE_ARG(0); + ra_.Emit(node, name, ctor, arg0); + break; + } + case 2: { + COMPILE_ARG(0); + COMPILE_ARG(1); + ra_.Emit(node, name, ctor, arg0, arg1, VReg::RegStart()); + break; + } + case 3: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + ra_.Emit(node, name, ctor, arg0, arg1, arg2); + break; + } + default: { + for (const auto *arg : arguments) { + auto ttctx = TargetTypeContext(this, arg->TsType()); + VReg argReg = AllocReg(); + arg->Compile(this); + StoreAccumulator(node, argReg); + } + + rra_.Emit(node, ctor, arguments.size() + 1, name, ctor); + break; + } + } + } + + template + void CallImpl(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + RegScope rs(this); + util::StringView name = signature->InternalName(); + + switch (arguments.size()) { + case 0: { + ra_.Emit(node, name, VReg::RegStart(), VReg::RegStart()); + break; + } + case 1: { + COMPILE_ARG(0); + ra_.Emit(node, name, arg0, VReg::RegStart()); + break; + } + case 2: { + COMPILE_ARG(0); + COMPILE_ARG(1); + ra_.Emit(node, name, arg0, arg1); + break; + } + case 3: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + ra_.Emit(node, name, arg0, arg1, arg2, VReg::RegStart()); + break; + } + case 4: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + COMPILE_ARG(3); + ra_.Emit(node, name, arg0, arg1, arg2, arg3); + break; + } + default: { + VReg argStart = NextReg(); + + for (const auto *arg : arguments) { + auto ttctx = TargetTypeContext(this, arg->TsType()); + VReg argReg = AllocReg(); + arg->Compile(this); + StoreAccumulator(node, argReg); + } + + rra_.Emit(node, argStart, arguments.size(), name, argStart); + break; + } + } + } + +#undef COMPILE_ARG + + void ToBinaryResult(const ir::AstNode *node, Label *ifFalse); + + template + void LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType); + void InitializeContainingClass(); + + friend class TargetTypeContext; + + VReg acc_ {}; + const checker::Type *targetType_ {}; + const checker::STSObjectType *containingClassType_ {}; +}; + +template +void STSGen::LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType) +{ + auto typeKind = targetType_ ? checker::STSChecker::TypeKind(targetType_) : targetType; + + switch (typeKind) { + case checker::TypeFlag::BYTE: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalByteType()); + break; + } + case checker::TypeFlag::CHAR: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalCharType()); + break; + } + case checker::TypeFlag::SHORT: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalShortType()); + break; + } + case checker::TypeFlag::INT: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalIntType()); + break; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalLongType()); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalFloatType()); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalDoubleType()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/STSemitter.cpp b/compiler/core/STSemitter.cpp new file mode 100644 index 000000000..e31c72897 --- /dev/null +++ b/compiler/core/STSemitter.cpp @@ -0,0 +1,584 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "STSemitter.h" + +#include "plugins/ecmascript/es2panda/compiler/core/STSGen.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" +#include "plugins/ecmascript/es2panda/ir/sts/stsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" +#include "assembly-program.h" + +namespace panda::es2panda::compiler { + +static constexpr auto EXTENSION = panda_file::SourceLang::PANDA_ASSEMBLY; + +static uint32_t TranslateModifierFlags(ir::ModifierFlags modifierFlags) +{ + uint32_t accessFlags = 0; + + if (modifierFlags & ir::ModifierFlags::PROTECTED) { + accessFlags = ACC_PROTECTED; + } else if (modifierFlags & ir::ModifierFlags::PRIVATE) { + accessFlags = ACC_PRIVATE; + } else { + accessFlags = ACC_PUBLIC; + } + + if (modifierFlags & ir::ModifierFlags::STATIC) { + accessFlags |= ACC_STATIC; + } + + if (modifierFlags & ir::ModifierFlags::CONST) { + accessFlags |= ACC_FINAL; + } + + return accessFlags; +} + +static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc) +{ + auto *funcScope = scriptFunc->Scope(); + auto *paramScope = funcScope->ParamScope(); + + auto func = pandasm::Function(funcScope->InternalName().Mutf8(), EXTENSION); + + func.params.reserve(paramScope->Params().size()); + + for (const auto *var : paramScope->Params()) { + std::stringstream ss; + var->TsType()->ToAssemblerType(ss); + func.params.emplace_back(pandasm::Type(ss.str(), var->TsType()->Rank()), EXTENSION); + } + + std::stringstream ss; + + if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) { + func.return_type = pandasm::Type(Signatures::PRIMITIVE_VOID, 0); + } else { + auto *returnType = scriptFunc->Signature()->ReturnType(); + + returnType->ToAssemblerType(ss); + ASSERT(!ss.str().empty()); + func.return_type = pandasm::Type(ss.str(), returnType->Rank()); + } + + if (!scriptFunc->IsStaticBlock()) { + const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc); + func.metadata->SetAccessFlags(TranslateModifierFlags(methodDef->Modifiers())); + } + + return func; +} + +pandasm::Function *STSFunctionEmitter::GenFunctionSignature() +{ + auto func = GenScriptFunction(cg_->RootNode()->AsScriptFunction()); + auto *funcElement = new pandasm::Function(func.name, func.language); + *funcElement = std::move(func); + programElement_->func = funcElement; + funcElement->regs_num = VReg::REG_START - cg_->TotalRegsNum(); + + return funcElement; +} + +void STSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + [[maybe_unused]] binder::LocalVariable *variable) const +{ + variableDebug.signature = Signatures::ANY; + variableDebug.signature_type = Signatures::ANY; +} + +void STSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) {} + +template +static pandasm::Function GenExternalFunction(T signature, bool isCtor) +{ + auto iter = signature.begin(); + std::string name(*iter++); + + auto func = pandasm::Function(name, EXTENSION); + + while (iter != signature.end()) { + auto paramName = *iter++; + func.params.emplace_back(pandasm::Type(paramName, 0), EXTENSION); + } + + func.return_type = pandasm::Type(Signatures::PRIMITIVE_VOID, 0); + if (isCtor) { + func.metadata->SetAttribute("ctor"); + } + func.metadata->SetAttribute("external"); + + return func; +} + +static pandasm::Function GenExternalFunction(checker::Signature *signature, bool isCtor) +{ + auto func = pandasm::Function(signature->InternalName().Mutf8(), EXTENSION); + + for (auto param : signature->Params()) { + auto *paramType = param->TsType(); + + std::stringstream ss; + paramType->ToAssemblerType(ss); + func.params.emplace_back(pandasm::Type(ss.str(), paramType->Rank()), EXTENSION); + } + + std::stringstream ss; + signature->ReturnType()->ToAssemblerType(ss); + func.return_type = pandasm::Type(ss.str(), signature->ReturnType()->Rank()); + + if (isCtor) { + func.metadata->SetAttribute("ctor"); + } + func.metadata->SetAttribute("external"); + + return func; +} + +void STSEmitter::GenAnnotation() +{ + prog_->lang = EXTENSION; + const auto *binder = static_cast(context_->Binder()); + + auto *globalRecordTable = binder->GetGlobalRecordTable(); + + for (auto *classDecl : globalRecordTable->ClassDefinitions()) { + GenClassRecord(classDecl, false); + } + + for (auto *interfaceDecl : globalRecordTable->InterfaceDeclarations()) { + GenInterfaceRecord(interfaceDecl, false); + } + + for (auto *signature : globalRecordTable->Signatures()) { + auto func = GenScriptFunction(signature->Node()->AsScriptFunction()); + prog_->function_table.emplace(func.name, std::move(func)); + } + + for (auto [extProg, recordTable] : binder->GetExternalRecordTable()) { + (void)extProg; + GenExternalRecord(recordTable); + } + + const auto *checker = static_cast(context_->Checker()); + + for (auto [arrType, signature] : checker->GlobalArrayTypes()) { + GenGlobalArrayRecord(arrType, signature); + } +} + +void STSEmitter::GenExternalRecord(binder::RecordTable *recordTable) +{ + for (auto *classDecl : recordTable->ClassDefinitions()) { + GenClassRecord(classDecl, true); + } + + for (auto *interfaceDecl : recordTable->InterfaceDeclarations()) { + GenInterfaceRecord(interfaceDecl, true); + } + + for (auto *signature : recordTable->Signatures()) { + auto func = GenScriptFunction(signature->Node()->AsScriptFunction()); + func.metadata->SetAttribute(Signatures::EXTERNAL); + prog_->function_table.emplace(func.name, std::move(func)); + } +} + +void STSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init) +{ + if (!init) { + return; + } + + const auto *type = init->TsType(); + + if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return; + } + + auto typeKind = checker::STSChecker::TypeKind(type); + + classField.metadata->SetFieldType(classField.type); + switch (typeKind) { + case checker::TypeFlag::STS_BOOLEAN: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsSTSBooleanType()->GetValue())); + break; + } + case checker::TypeFlag::BYTE: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsByteType()->GetValue())); + break; + } + case checker::TypeFlag::SHORT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsShortType()->GetValue())); + break; + } + case checker::TypeFlag::INT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsIntType()->GetValue())); + break; + } + case checker::TypeFlag::LONG: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsLongType()->GetValue())); + break; + } + case checker::TypeFlag::FLOAT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsFloatType()->GetValue())); + break; + } + case checker::TypeFlag::DOUBLE: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsDoubleType()->GetValue())); + break; + } + case checker::TypeFlag::CHAR: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsCharType()->GetValue())); + break; + } + case checker::TypeFlag::STS_OBJECT: { + classField.metadata->SetValue(pandasm::ScalarValue::Create( + type->AsSTSObjectType()->AsSTSStringType()->GetValue().Mutf8())); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void STSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef) +{ + auto *scriptFunc = methodDef->Function(); + + if (scriptFunc->Body()) { + return; + } + + auto func = GenScriptFunction(scriptFunc); + func.metadata->SetAccessFlags(func.metadata->GetAccessFlags() | ACC_ABSTRACT); + prog_->function_table.emplace(func.name, std::move(func)); +} + +void STSEmitter::GenClassField(const ir::ClassProperty *field, pandasm::Record &classRecord, bool external) +{ + auto classField = pandasm::Field(prog_->lang); + const auto *ident = field->Id(); + std::stringstream ss; + field->TsType()->ToAssemblerType(ss); + + classField.name = ident->Name().Mutf8(); + classField.type = pandasm::Type(ss.str(), field->TsType()->Rank()); + + classField.metadata->SetAccessFlags(TranslateModifierFlags(field->Modifiers())); + + if (external) { + classField.metadata->SetAttribute(Signatures::EXTERNAL); + } else { + EmitDefaultFieldValue(classField, field->Value()); + } + classRecord.field_list.emplace_back(std::move(classField)); +} + +void STSEmitter::GenClassInheritedFields(const checker::STSObjectType *baseType, pandasm::Record &classRecord) +{ + std::vector foreignProps = baseType->ForeignProperties(); + + for (const auto *foreignProp : foreignProps) { + auto *declNode = foreignProp->Declaration()->Node(); + if (!declNode->IsClassProperty()) { + continue; + } + + GenClassField(declNode->AsClassProperty(), classRecord, true); + } +} + +void STSEmitter::GenGlobalArrayRecord(checker::STSArrayType *arrayType, checker::Signature *signature) +{ + std::stringstream ss; + arrayType->ToAssemblerType(ss); + + auto arrayRecord = pandasm::Record(ss.str(), prog_->lang); + + auto func = GenExternalFunction(signature, true); + func.params.emplace(func.params.begin(), pandasm::Type(ss.str(), 0), EXTENSION); + + prog_->function_table.emplace(func.name, std::move(func)); + + arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL); + prog_->record_table.emplace(arrayRecord.name, std::move(arrayRecord)); +} + +void STSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external) +{ + auto *baseType = interfaceDecl->TsType()->AsSTSObjectType(); + + auto interfaceRecord = pandasm::Record(baseType->Name().Mutf8(), prog_->lang); + + if (external) { + interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL); + } + + uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE; + + if (interfaceDecl->IsStatic()) { + accessFlags |= ACC_STATIC; + } + + interfaceRecord.metadata->SetAccessFlags(accessFlags); + interfaceRecord.source_file = context_->Binder()->Program()->SourceFile().Mutf8(); + interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); + + for (auto *it : baseType->Interfaces()) { + interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, it->Name().Mutf8()); + } + + GenClassInheritedFields(baseType, interfaceRecord); + + for (const auto *prop : interfaceDecl->Body()->Body()) { + if (prop->IsClassProperty()) { + GenClassField(prop->AsClassProperty(), interfaceRecord, false); + } else if (prop->IsMethodDefinition()) { + GenInterfaceMethodDefinition(prop->AsMethodDefinition()); + } + } + + prog_->record_table.emplace(interfaceRecord.name, std::move(interfaceRecord)); +} + +void STSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external) +{ + auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), prog_->lang); + + if (external) { + classRecord.metadata->SetAttribute(Signatures::EXTERNAL); + } + + uint32_t accessFlags = ACC_PUBLIC; + + if (classDef->IsAbstract()) { + accessFlags |= ACC_ABSTRACT; + } + + if (!classDef->IsOpen()) { + accessFlags |= ACC_FINAL; + } + + if (classDef->IsStatic()) { + accessFlags |= ACC_STATIC; + } + + classRecord.metadata->SetAccessFlags(accessFlags); + classRecord.source_file = context_->Binder()->Program()->SourceFile().Mutf8(); + + auto *baseType = classDef->TsType()->AsSTSObjectType(); + + if (baseType->SuperType()) { + classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, + baseType->SuperType()->AssemblerName().Mutf8()); + } else { + classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); + } + + for (auto *it : baseType->Interfaces()) { + classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, it->Name().Mutf8()); + } + + if (!classDef->IsAbstract()) { + GenClassInheritedFields(baseType, classRecord); + } + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty()) { + continue; + } + + GenClassField(prop->AsClassProperty(), classRecord, external); + } + + std::vector annotations; + if (classDef->TypeParams()) { + annotations.emplace_back(GenAnnotationSignature(classDef)); + } + + const ir::AstNode *parent = classDef->Parent(); + while (parent != nullptr) { + if (parent->IsMethodDefinition()) { + annotations.emplace_back(GenAnnotationEnclosingMethod(parent->AsMethodDefinition())); + annotations.emplace_back(GenAnnotationInnerClass(classDef, parent)); + break; + } + if (parent->IsClassDefinition()) { + annotations.emplace_back(GenAnnotationEnclosingClass( + parent->AsClassDefinition()->TsType()->AsSTSObjectType()->AssemblerName().Utf8())); + annotations.emplace_back(GenAnnotationInnerClass(classDef, parent)); + break; + } + parent = parent->Parent(); + } + + if (!annotations.empty()) { + classRecord.metadata->SetAnnotations(std::move(annotations)); + } + + prog_->record_table.emplace(classRecord.name, std::move(classRecord)); +} + +pandasm::AnnotationData STSEmitter::GenAnnotationSignature(const ir::ClassDefinition *classDef) +{ + static constexpr std::string_view object = "Lets/lang/Object;"; + std::vector parts {}; + std::stringstream ss {}; + const auto ¶ms = classDef->TypeParams()->Params(); + + bool firstIteration = true; + for (const auto *param : params) { + if (firstIteration) { + ss << Signatures::GENERIC_BEGIN; + firstIteration = false; + } + ss << param->Name()->Name() << Signatures::MANGLE_BEGIN; + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + std::stringstream {}.swap(ss); + if (!param->Constraint()) { + ss << object; + } else { + param->Constraint()->AsSTSTypeReference()->TsType()->ToAssemblerType(ss); + auto str = ss.str(); + std::replace(str.begin(), str.end(), *Signatures::METHOD_SEPARATOR.begin(), + *Signatures::NAMESPACE_SEPARATOR.begin()); + std::stringstream {}.swap(ss); + ss << Signatures::CLASS_REF_BEGIN << str << Signatures::MANGLE_SEPARATOR; + } + + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + std::stringstream {}.swap(ss); // cleanup + } + + ss << Signatures::GENERIC_END; + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + std::stringstream {}.swap(ss); + if (!classDef->TsType()->AsSTSObjectType()->SuperType()) { + ss << object; + } else { + ss << Signatures::CLASS_REF_BEGIN; + auto superType = classDef->TsType()->AsSTSObjectType()->SuperType()->AssemblerName().Mutf8(); + std::replace(superType.begin(), superType.end(), *Signatures::MANGLE_SEPARATOR.begin(), + *Signatures::NAMESPACE_SEPARATOR.begin()); + ss << superType << Signatures::MANGLE_SEPARATOR; + } + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + GenAnnotation(Signatures::DALVIK_ANNOTATION_SIGNATURE); + pandasm::AnnotationData signature(Signatures::DALVIK_ANNOTATION_SIGNATURE); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique(pandasm::Value::Type::STRING, std::move(parts))); + signature.AddElement(std::move(value)); + return signature; +} + +pandasm::AnnotationData STSEmitter::GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef) +{ + GenAnnotation(Signatures::DALVIK_ANNOTATION_ENCLOSING_METHOD); + pandasm::AnnotationData enclosing_method(Signatures::DALVIK_ANNOTATION_ENCLOSING_METHOD); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique(pandasm::ScalarValue::Create( + methodDef->Function()->Scope()->InternalName().Mutf8()))); + enclosing_method.AddElement(std::move(value)); + return enclosing_method; +} + +pandasm::AnnotationData STSEmitter::GenAnnotationEnclosingClass(std::string_view className) +{ + GenAnnotation(Signatures::DALVIK_ANNOTATION_ENCLOSING_CLASS); + pandasm::AnnotationData enclosingClass(Signatures::DALVIK_ANNOTATION_ENCLOSING_CLASS); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique( + pandasm::ScalarValue::Create(pandasm::Type::FromName(className, true)))); + enclosingClass.AddElement(std::move(value)); + return enclosingClass; +} + +pandasm::AnnotationData STSEmitter::GenAnnotationInnerClass(const ir::ClassDefinition *classDef, + const ir::AstNode *parent) +{ + GenAnnotation(Signatures::DALVIK_ANNOTATION_INNER_CLASS); + pandasm::AnnotationData innerClass(Signatures::DALVIK_ANNOTATION_INNER_CLASS); + const bool isAnonymous = classDef->Modifiers() & ir::ClassDefinitionModifiers::ANONYMOUS; + pandasm::AnnotationElement name(Signatures::ANNOTATION_KEY_NAME, + std::make_unique( + isAnonymous + ? pandasm::ScalarValue::Create(0) + : pandasm::ScalarValue::Create( + classDef->TsType()->AsSTSObjectType()->AssemblerName().Mutf8()))); + innerClass.AddElement(std::move(name)); + + pandasm::AnnotationElement accessFlags( + Signatures::ANNOTATION_KEY_ACCESS_FLAGS, + std::make_unique( + pandasm::ScalarValue::Create(TranslateModifierFlags(parent->Modifiers())))); + innerClass.AddElement(std::move(accessFlags)); + return innerClass; +} + +void STSEmitter::GenAnnotation(std::string_view recordNameView, bool isRuntime, bool isType) +{ + const std::string recordName(recordNameView); + const auto recordIt = prog_->record_table.find(recordName); + if (recordIt == prog_->record_table.end()) { + pandasm::Record record(recordName, EXTENSION); + record.metadata->SetAttribute(Signatures::EXTERNAL); + record.metadata->SetAttribute(Signatures::ANNOTATION_ATTRIBUTE); + if (isRuntime && isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, + Signatures::RUNTIME_TYPE_ANNOTATION); + } else if (isRuntime && !isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::RUNTIME_ANNOTATION); + } else if (!isRuntime && isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::TYPE_ANNOTATION); + } + prog_->record_table.emplace(record.name, std::move(record)); + } +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/STSemitter.h b/compiler/core/STSemitter.h new file mode 100644 index 000000000..ae46fac92 --- /dev/null +++ b/compiler/core/STSemitter.h @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_STS_EMITTER_H +#define ES2PANDA_COMPILER_CORE_STS_EMITTER_H + +#include "emitter.h" + +namespace panda::es2panda::binder { +class RecordTable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::ir { +class ClassDefinition; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class STSObjectType; +class STSArrayType; +class Signature; +} // namespace panda::es2panda::checker + +namespace panda::pandasm { +struct Field; +struct Record; +struct ItemMetadata; +struct AnnotationData; +} // namespace panda::pandasm + +namespace panda::es2panda::compiler { + +class STSFunctionEmitter : public FunctionEmitter { +public: + STSFunctionEmitter(const CodeGen *cg, ProgramElement *programElement) : FunctionEmitter(cg, programElement) {} + ~STSFunctionEmitter() = default; + NO_COPY_SEMANTIC(STSFunctionEmitter); + NO_MOVE_SEMANTIC(STSFunctionEmitter); + +protected: + const STSGen *Stsg() const + { + return reinterpret_cast(cg_); + } + + pandasm::Function *GenFunctionSignature() override; + + void GenFunctionAnnotations(pandasm::Function *func) override; + void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const override; +}; + +class STSEmitter : public Emitter { +public: + explicit STSEmitter(const CompilerContext *context) : Emitter(context) {} + virtual ~STSEmitter() = default; + NO_COPY_SEMANTIC(STSEmitter); + NO_MOVE_SEMANTIC(STSEmitter); + + void GenAnnotation() override; + +private: + void GenExternalRecord(binder::RecordTable *recordTable); + void GenGlobalArrayRecord(checker::STSArrayType *arrType, checker::Signature *signature); + void GenClassRecord(const ir::ClassDefinition *classDef, bool external); + void GenAnnotation(std::string_view record_name, bool isRuntime = false, bool isType = false); + void GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external); + void EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init); + void GenClassField(const ir::ClassProperty *field, pandasm::Record &classRecord, bool external); + void GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef); + void GenClassInheritedFields(const checker::STSObjectType *baseType, pandasm::Record &classRecord); + pandasm::AnnotationData GenAnnotationSignature(const ir::ClassDefinition *classDef); + pandasm::AnnotationData GenAnnotationEnclosingClass(std::string_view className); + pandasm::AnnotationData GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef); + pandasm::AnnotationData GenAnnotationInnerClass(const ir::ClassDefinition *classDef, const ir::AstNode *parent); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/STSfunction.cpp b/compiler/core/STSfunction.cpp new file mode 100644 index 000000000..a935026b7 --- /dev/null +++ b/compiler/core/STSfunction.cpp @@ -0,0 +1,159 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "STSfunction.h" + +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/compiler/base/lreference.h" +#include "plugins/ecmascript/es2panda/compiler/core/STSGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/envScope.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/checker/types/sts/types.h" + +namespace panda::es2panda::compiler { +void STSFunction::CallImplicitCtor(STSGen *stsg) +{ + RegScope rs(stsg); + auto *superType = stsg->ContainingClassType()->SuperType(); + + if (!superType) { + stsg->CallThisStatic0(stsg->RootNode(), stsg->GetThisReg(), Signatures::BUILTIN_OBJECT_CTOR); + + return; + } + + auto res = std::find_if(superType->ConstructSignatures().cbegin(), superType->ConstructSignatures().cend(), + [](const checker::Signature *sig) { return sig->Params().empty(); }); + + if (res == superType->ConstructSignatures().cend()) { + return; + } + + stsg->CallThisStatic0(stsg->RootNode(), stsg->GetThisReg(), (*res)->InternalName()); +} + +void STSFunction::CompileSourceBlock(STSGen *stsg, const ir::BlockStatement *block) +{ + auto *scriptFunc = stsg->RootNode()->AsScriptFunction(); + + if (scriptFunc->IsStaticBlock()) { + const auto *classDef = stsg->ContainingClassType()->GetDeclNode()->AsClassDefinition(); + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty() || !prop->IsStatic()) { + continue; + } + + prop->AsClassProperty()->Compile(stsg); + } + } else if (scriptFunc->IsConstructor()) { + if (scriptFunc->IsImplicitConstructor()) { + CallImplicitCtor(stsg); + } + + const auto *classDef = stsg->ContainingClassType()->GetDeclNode()->AsClassDefinition(); + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty() || prop->IsStatic()) { + continue; + } + + prop->AsClassProperty()->Compile(stsg); + } + } + + const auto &statements = block->Statements(); + + if (statements.empty()) { + stsg->SetFirstStmt(block); + stsg->EmitReturnVoid(block); + return; + } + + stsg->SetFirstStmt(statements.front()); + + stsg->CompileStatementList(statements); + + if (!statements.back()->IsReturnStatement()) { + if (stsg->ReturnType()->IsSTSVoidType()) { + stsg->EmitReturnVoid(statements.back()); + } else { + stsg->LoadDefaultValue(statements.back(), scriptFunc->Signature()->ReturnType()); + stsg->ReturnAcc(statements.back()); + } + } +} + +void STSFunction::CompileFunctionParameterDeclaration(STSGen *stsg, const ir::ScriptFunction *func) +{ + ScopeContext scopeCtx(stsg, func->Scope()->ParamScope()); + + uint32_t index = 0; + + for (const auto *param : func->Params()) { + if (!param->IsRestElement()) { + index++; + continue; + } + + auto ref = JSLReference::Create(stsg, param, true); + [[maybe_unused]] binder::Variable *paramVar = ref.Variable(); + ASSERT(paramVar && paramVar->IsLocalVariable()); + + VReg paramReg = VReg(binder::Binder::MANDATORY_PARAMS_NUMBER + VReg::PARAM_START + index++); + ASSERT(paramVar->AsLocalVariable()->Vreg() == paramReg); + + ref.SetValue(); + index++; + } +} + +void STSFunction::CompileFunction(STSGen *stsg) +{ + const auto *decl = stsg->RootNode()->AsScriptFunction(); + CompileFunctionParameterDeclaration(stsg, decl); + + const ir::AstNode *body = decl->Body(); + + if (body->IsExpression()) { + // TODO + } else { + CompileSourceBlock(stsg, body->AsBlockStatement()); + } +} +void STSFunction::Compile(STSGen *stsg) +{ + FunctionRegScope lrs(stsg); + auto *topScope = stsg->TopScope(); + + if (topScope->IsFunctionScope()) { + CompileFunction(stsg); + } else { + ASSERT(topScope->IsGlobalScope()); + CompileSourceBlock(stsg, stsg->RootNode()->AsBlockStatement()); + } + + stsg->SortCatchTables(); +} + +} // namespace panda::es2panda::compiler diff --git a/compiler/core/STSfunction.h b/compiler/core/STSfunction.h new file mode 100644 index 000000000..3583ac427 --- /dev/null +++ b/compiler/core/STSfunction.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_STSFUNCTION_H +#define ES2PANDA_COMPILER_CORE_STSFUNCTION_H + +#include "plugins/ecmascript/es2panda/ir/irnode.h" + +namespace panda::es2panda::ir { +class ScriptFunction; +class BlockStatement; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::compiler { +class STSGen; + +class STSFunction { +public: + STSFunction() = delete; + + static void Compile(STSGen *stsg); + +private: + static void CompileSourceBlock(STSGen *stsg, const ir::BlockStatement *block); + static void CompileFunctionParameterDeclaration(STSGen *stsg, const ir::ScriptFunction *func); + static void CompileFunction(STSGen *stsg); + static void CallImplicitCtor(STSGen *stsg); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/codeGen.cpp b/compiler/core/codeGen.cpp new file mode 100644 index 000000000..af9e56e67 --- /dev/null +++ b/compiler/core/codeGen.cpp @@ -0,0 +1,196 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "codeGen.h" + +#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" +#include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" +#include "plugins/ecmascript/es2panda/compiler/core/regScope.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/compiler/core/dynamicContext.h" +#include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" + +namespace panda::es2panda::compiler { +Label *CodeGen::AllocLabel() +{ + std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++); + return sa_.AllocLabel(std::move(id)); +} + +bool CodeGen::IsDebug() const +{ + return context_->IsDebug(); +} + +uint32_t CodeGen::ParamCount() const +{ + if (rootNode_->IsProgram()) { + return 0; + } + + return rootNode_->AsScriptFunction()->Params().size(); +} + +uint32_t CodeGen::FormalParametersCount() const +{ + if (rootNode_->IsProgram()) { + return 0; + } + + ASSERT(rootNode_->IsScriptFunction()); + + return rootNode_->AsScriptFunction()->FormalParamsLength(); +} + +uint32_t CodeGen::InternalParamCount() const +{ + static const uint32_t HIDDEN_PARAMS = 3; + return ParamCount() + HIDDEN_PARAMS; +} + +const util::StringView &CodeGen::InternalName() const +{ + return topScope_->InternalName(); +} + +const util::StringView &CodeGen::FunctionName() const +{ + return topScope_->Name(); +} + +binder::Binder *CodeGen::Binder() const +{ + return context_->Binder(); +} + +int32_t CodeGen::AddLiteralBuffer(LiteralBuffer &&buf) +{ + programElement_->buffStorage.emplace_back(std::move(buf)); + return literalBufferIdx_++; +} + +void CodeGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str) +{ + sa_.Emit(node, str); +} + +void CodeGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label) +{ + sa_.AddLabel(label); +} + +void CodeGen::Branch(const ir::AstNode *node, Label *label) +{ + sa_.Emit(node, label); +} + +bool CodeGen::CheckControlFlowChange() +{ + const auto *iter = dynamicContext_; + + while (iter) { + if (iter->HasFinalizer()) { + return true; + } + + iter = iter->Prev(); + } + + return false; +} + +Label *CodeGen::ControlFlowChangeBreak(const ir::Identifier *label) +{ + auto *iter = dynamicContext_; + + util::StringView labelName = label ? label->Name() : LabelTarget::BREAK_LABEL; + Label *breakTarget = nullptr; + + while (iter) { + iter->AbortContext(ControlFlowChange::BREAK, labelName); + + const auto &labelTargetName = iter->Target().BreakLabel(); + + if (iter->Target().BreakTarget()) { + breakTarget = iter->Target().BreakTarget(); + } + + if (labelTargetName == labelName) { + break; + } + + iter = iter->Prev(); + } + + return breakTarget; +} + +Label *CodeGen::ControlFlowChangeContinue(const ir::Identifier *label) +{ + auto *iter = dynamicContext_; + util::StringView labelName = label ? label->Name() : LabelTarget::CONTINUE_LABEL; + Label *continueTarget = nullptr; + + while (iter) { + iter->AbortContext(ControlFlowChange::CONTINUE, labelName); + + const auto &labelTargetName = iter->Target().ContinueLabel(); + + if (iter->Target().ContinueTarget()) { + continueTarget = iter->Target().ContinueTarget(); + } + + if (labelTargetName == labelName) { + break; + } + + iter = iter->Prev(); + } + + return continueTarget; +} + +uint32_t CodeGen::TryDepth() const +{ + const auto *iter = dynamicContext_; + uint32_t depth = 0; + + while (iter) { + if (iter->HasTryCatch()) { + depth++; + } + + iter = iter->Prev(); + } + + return depth; +} + +CatchTable *CodeGen::CreateCatchTable() +{ + auto *catchTable = allocator_->New(this, TryDepth()); + catchList_.push_back(catchTable); + return catchTable; +} + +void CodeGen::SortCatchTables() +{ + std::sort(catchList_.begin(), catchList_.end(), + [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); }); +} + +} // namespace panda::es2panda::compiler diff --git a/compiler/core/codeGen.h b/compiler/core/codeGen.h new file mode 100644 index 000000000..a0c42f692 --- /dev/null +++ b/compiler/core/codeGen.h @@ -0,0 +1,208 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_CODEGEN_H +#define ES2PANDA_COMPILER_CORE_CODEGEN_H + +#include "plugins/ecmascript/es2panda/compiler/base/literals.h" +#include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" +#include "plugins/ecmascript/es2panda/compiler/core/regScope.h" + +namespace panda::es2panda::compiler { +class CatchTable; +class DynamicContext; + +enum class Constant { + JS_NAN, + JS_HOLE, + JS_INFINITY, + JS_UNDEFINED, + JS_NULL, + JS_TRUE, + JS_FALSE, + JS_SYMBOL, + JS_GLOBAL, +}; + +class DebugInfo { +public: + explicit DebugInfo(ArenaAllocator *allocator) : variableDebugInfo(allocator->Adapter()) {}; + DEFAULT_COPY_SEMANTIC(DebugInfo); + DEFAULT_MOVE_SEMANTIC(DebugInfo); + ~DebugInfo() = default; + + ArenaVector variableDebugInfo; + const ir::Statement *firstStmt {}; +}; + +class CodeGen { +public: + explicit CodeGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : allocator_(allocator), + context_(context), + debugInfo_(allocator_), + topScope_(scope), + scope_(topScope_), + rootNode_(scope->Node()), + insns_(allocator_->Adapter()), + catchList_(allocator_->Adapter()), + programElement_(programElement), + sa_(this), + ra_(this, spiller), + rra_(this, spiller) + { + } + ~CodeGen() = default; + NO_COPY_SEMANTIC(CodeGen); + NO_MOVE_SEMANTIC(CodeGen); + + static constexpr auto MAX_RANGE_CALL_ARG = 128; + + inline ArenaAllocator *Allocator() const + { + return allocator_; + } + + const ArenaVector &CatchList() const + { + return catchList_; + } + + binder::FunctionScope *TopScope() const + { + return topScope_; + } + + binder::Scope *Scope() const + { + return scope_; + } + + const ir::AstNode *RootNode() const + { + return rootNode_; + } + + ArenaList &Insns() + { + return insns_; + } + + const ArenaList &Insns() const + { + return insns_; + } + + VReg AllocReg() + { + return VReg(usedRegs_--); + } + + VReg AllocReg(const checker::Type *type) + { + return VReg(usedRegs_--, type); + } + + VReg NextReg() const + { + return VReg(usedRegs_); + } + + uint32_t TotalRegsNum() const + { + return totalRegs_; + } + + size_t LabelCount() const + { + return labelId_; + } + + const DebugInfo &Debuginfo() const + { + return debugInfo_; + } + + uint32_t IcSize() const + { + return 0; + } + + bool IsDebug() const; + RegSpiller *GetRegSpiller() const; + uint32_t ParamCount() const; + uint32_t FormalParametersCount() const; + uint32_t InternalParamCount() const; + const util::StringView &InternalName() const; + const util::StringView &FunctionName() const; + binder::Binder *Binder() const; + + Label *AllocLabel(); + int32_t AddLiteralBuffer(LiteralBuffer &&buf); + + void LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str); + + void SetLabel(const ir::AstNode *node, Label *label); + void Branch(const ir::AstNode *node, class Label *label); + bool CheckControlFlowChange(); + Label *ControlFlowChangeBreak(const ir::Identifier *label = nullptr); + Label *ControlFlowChangeContinue(const ir::Identifier *label); + + uint32_t TryDepth() const; + CatchTable *CreateCatchTable(); + void SortCatchTables(); + + void SetFirstStmt(const ir::Statement *stmt) + { + debugInfo_.firstStmt = stmt; + } + + [[noreturn]] static void Unimplemented() + { + throw Error(ErrorType::GENERIC, "", "Unimplemented code path"); + } + +protected: + ArenaAllocator *allocator_; + CompilerContext *context_; + DebugInfo debugInfo_; + binder::FunctionScope *topScope_; + binder::Scope *scope_; + const ir::AstNode *rootNode_; + ArenaList insns_; + ArenaVector catchList_; + ProgramElement *programElement_; + DynamicContext *dynamicContext_ {}; + + SimpleAllocator sa_; + RegAllocator ra_; + RangeRegAllocator rra_; + size_t labelId_ {0}; + int32_t literalBufferIdx_ {0}; + + uint32_t usedRegs_ {VReg::REG_START}; + uint32_t totalRegs_ {VReg::REG_START}; + friend class ScopeContext; + friend class RegScope; + friend class LocalRegScope; + friend class LoopRegScope; + friend class ParamRegScope; + friend class FunctionRegScope; + friend class DynamicContext; +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/compileJob.cpp b/compiler/core/compileJob.cpp new file mode 100644 index 000000000..419ca79d6 --- /dev/null +++ b/compiler/core/compileJob.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "compileQueue.h" + +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" + +namespace panda::es2panda::compiler { + +void CompileJob::Run() +{ + std::unique_lock lock(m_); + cond_.wait(lock, [this] { return dependencies_ == 0; }); + + context_->GetCodeGenCb()(context_, scope_, &programElement_); + + if (dependant_) { + dependant_->Signal(); + } +} + +void CompileJob::DependsOn(CompileJob *job) +{ + job->dependant_ = this; + dependencies_++; +} + +void CompileJob::Signal() +{ + { + std::lock_guard lock(m_); + dependencies_--; + } + + cond_.notify_one(); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/compileJob.h b/compiler/core/compileJob.h new file mode 100644 index 000000000..687217f77 --- /dev/null +++ b/compiler/core/compileJob.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_COMPILEJOB_H +#define ES2PANDA_COMPILER_CORE_COMPILEJOB_H + +#include "macros.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/programElement.h" + +#include +#include + +namespace panda::es2panda::binder { +class FunctionScope; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::compiler { +class CompilerContext; +class ProgramElement; + +class CompileJob { +public: + CompileJob() = default; + NO_COPY_SEMANTIC(CompileJob); + NO_MOVE_SEMANTIC(CompileJob); + ~CompileJob() = default; + + const ProgramElement *GetProgramElement() const + { + return &programElement_; + } + + ProgramElement *GetProgramElement() + { + return &programElement_; + } + + void SetConext(CompilerContext *context, binder::FunctionScope *scope) + { + context_ = context; + scope_ = scope; + } + + void Run(); + void DependsOn(CompileJob *job); + void Signal(); + +private: + std::mutex m_; + std::condition_variable cond_; + CompilerContext *context_ {}; + binder::FunctionScope *scope_ {}; + ProgramElement programElement_; + CompileJob *dependant_ {}; + size_t dependencies_ {0}; +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/compileQueue.cpp b/compiler/core/compileQueue.cpp index f75127362..6af577190 100644 --- a/compiler/core/compileQueue.cpp +++ b/compiler/core/compileQueue.cpp @@ -23,43 +23,6 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" namespace panda::es2panda::compiler { -CompileJob::CompileJob() : programElement_(std::make_unique()) {} -CompileJob::~CompileJob() = default; - -void CompileJob::Run() -{ - std::unique_lock lock(m_); - cond_.wait(lock, [this] { return dependencies_ == 0; }); - - ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); - PandaGen pg(&allocator, context_, scope_, programElement_.get()); - - Function::Compile(&pg); - - FunctionEmitter funcEmitter(&pg, programElement_.get()); - funcEmitter.Generate(); - - if (dependant_ != nullptr) { - dependant_->Signal(); - } -} - -void CompileJob::DependsOn(CompileJob *job) -{ - job->dependant_ = this; - dependencies_++; -} - -void CompileJob::Signal() -{ - { - std::lock_guard lock(m_); - dependencies_--; - } - - cond_.notify_one(); -} - CompileQueue::CompileQueue(size_t threadCount) { threads_.reserve(threadCount); @@ -147,15 +110,16 @@ void CompileQueue::Wait(const JobsFinishedCb &onFinishedCb) std::unique_lock lock(m_); jobsFinished_.wait(lock, [this]() { return activeWorkers_ == 0 && jobsCount_ == 0; }); + if (!errors_.empty()) { + delete[] jobs_; + // NOLINTNEXTLINE + throw errors_.front(); + } + for (uint32_t i = 0; i < totalJobsCount_; i++) { onFinishedCb(jobs_ + i); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } delete[] jobs_; - - if (!errors_.empty()) { - // NOLINTNEXTLINE - throw errors_.front(); - } } } // namespace panda::es2panda::compiler diff --git a/compiler/core/compileQueue.h b/compiler/core/compileQueue.h index 39d39f1bc..bd31c32f5 100644 --- a/compiler/core/compileQueue.h +++ b/compiler/core/compileQueue.h @@ -19,6 +19,7 @@ #include "macros.h" #include "os/thread.h" #include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileJob.h" #include #include @@ -30,39 +31,6 @@ class FunctionScope; namespace panda::es2panda::compiler { class CompilerContext; -class ProgramElement; - -class CompileJob { -public: - CompileJob(); - NO_COPY_SEMANTIC(CompileJob); - NO_MOVE_SEMANTIC(CompileJob); - ~CompileJob(); - - ProgramElement *GetProgramElement() const - { - return programElement_.get(); - } - - void SetConext(CompilerContext *context, binder::FunctionScope *scope) - { - context_ = context; - scope_ = scope; - } - - void Run(); - void DependsOn(CompileJob *job); - void Signal(); - -private: - std::mutex m_; - std::condition_variable cond_; - CompilerContext *context_ {}; - binder::FunctionScope *scope_ {}; - std::unique_ptr programElement_; - CompileJob *dependant_ {}; - size_t dependencies_ {0}; -}; class CompileQueue { public: diff --git a/compiler/core/compilerContext.cpp b/compiler/core/compilerContext.cpp index 209d223a9..c071e9f44 100644 --- a/compiler/core/compilerContext.cpp +++ b/compiler/core/compilerContext.cpp @@ -16,14 +16,5 @@ #include "compilerContext.h" #include -#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" -#include "plugins/ecmascript/es2panda/compiler/base/literals.h" - namespace panda::es2panda::compiler { -CompilerContext::CompilerContext(binder::Binder *binder, CompilerOptions options) - : binder_(binder), emitter_(std::make_unique(this)), options_(options) -{ -} - -CompilerContext::~CompilerContext() = default; } // namespace panda::es2panda::compiler diff --git a/compiler/core/compilerContext.h b/compiler/core/compilerContext.h index 7936fc1ab..3e348d6e5 100644 --- a/compiler/core/compilerContext.h +++ b/compiler/core/compilerContext.h @@ -23,34 +23,60 @@ #include -namespace panda::es2panda::ir { -class Literal; -} // namespace panda::es2panda::ir - namespace panda::es2panda::binder { class Binder; +class FunctionScope; } // namespace panda::es2panda::binder +namespace panda::es2panda::checker { +class Checker; +} // namespace panda::es2panda::checker + namespace panda::es2panda::compiler { class Literal; class DebugInfo; class Emitter; +class CodeGen; +class ProgramElement; class CompilerContext { public: - CompilerContext(binder::Binder *binder, CompilerOptions options); + using CodeGenCb = + std::function; + + CompilerContext(binder::Binder *binder, checker::Checker *checker, CompilerOptions options, + const CodeGenCb &codeGenCb) + : binder_(binder), checker_(checker), options_(options), codeGenCb_(codeGenCb) + { + } + NO_COPY_SEMANTIC(CompilerContext); NO_MOVE_SEMANTIC(CompilerContext); - ~CompilerContext(); + ~CompilerContext() = default; binder::Binder *Binder() const { return binder_; } + checker::Checker *Checker() const + { + return checker_; + } + Emitter *GetEmitter() const { - return emitter_.get(); + return emitter_; + } + + void SetEmitter(Emitter *emitter) + { + emitter_ = emitter; + } + + const CodeGenCb &GetCodeGenCb() const + { + return codeGenCb_; } int32_t AddContextLiteral(LiteralBuffer &&literals) @@ -69,6 +95,11 @@ public: return options_.isDebug; } + bool DumpDebugInfo() const + { + return options_.dumpDebugInfo; + } + bool IsDirectEval() const { return options_.isDirectEval; @@ -86,9 +117,11 @@ public: private: binder::Binder *binder_; + checker::Checker *checker_; + Emitter *emitter_ {}; std::vector buffStorage_; - std::unique_ptr emitter_; CompilerOptions options_; + CodeGenCb codeGenCb_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/compilerImpl.cpp b/compiler/core/compilerImpl.cpp index 1531ad8ec..72e5f8c16 100644 --- a/compiler/core/compilerImpl.cpp +++ b/compiler/core/compilerImpl.cpp @@ -15,10 +15,27 @@ #include "compilerImpl.h" -#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" #include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" -#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerImpl.h" +#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/STSGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/JSemitter.h" +#include "plugins/ecmascript/es2panda/compiler/core/STSemitter.h" +#include "plugins/ecmascript/es2panda/parser/parserImpl.h" +#include "plugins/ecmascript/es2panda/parser/JSparser.h" +#include "plugins/ecmascript/es2panda/parser/ASparser.h" +#include "plugins/ecmascript/es2panda/parser/TSparser.h" +#include "plugins/ecmascript/es2panda/parser/STSparser.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/binder/JSBinder.h" +#include "plugins/ecmascript/es2panda/binder/ASBinder.h" +#include "plugins/ecmascript/es2panda/binder/TSBinder.h" +#include "plugins/ecmascript/es2panda/binder/STSBinder.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/STSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ASchecker.h" +#include "plugins/ecmascript/es2panda/checker/JSchecker.h" #include "plugins/ecmascript/es2panda/es2panda.h" #include "plugins/ecmascript/es2panda/parser/program/program.h" @@ -26,15 +43,8 @@ #include namespace panda::es2panda::compiler { -CompilerImpl::CompilerImpl(size_t threadCount) : queue_(new CompileQueue(threadCount)) {} - -CompilerImpl::~CompilerImpl() -{ - delete queue_; -} -panda::pandasm::Program *CompilerImpl::Compile(CompilerContext *context, parser::Program *program, - const es2panda::CompilerOptions &options) +void CompilerImpl::HandleContextLiterals(CompilerContext *context) { auto *emitter = context->GetEmitter(); @@ -44,27 +54,98 @@ panda::pandasm::Program *CompilerImpl::Compile(CompilerContext *context, parser: } emitter->LiteralBufferIndex() += context->ContextLiterals().size(); +} - if (program->Extension() == ScriptExtension::AS) { - /* TODO(): AS files are not yet compiled */ - return nullptr; - } +panda::pandasm::Program *CompilerImpl::Emit(CompilerContext *context) +{ + HandleContextLiterals(context); + + queue_.Schedule(context); + + /* Main thread can also be used instead of idling */ + queue_.Consume(); + auto *emitter = context->GetEmitter(); + queue_.Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); - if (program->Extension() == ScriptExtension::TS) { - ArenaAllocator localAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); - auto checker = std::make_unique(&localAllocator, context->Binder()); - checker->StartChecker(); + return emitter->Finalize(context->DumpDebugInfo()); +} +template +static CompilerContext::CodeGenCb MakeCompileJob() +{ + return + [](CompilerContext *context, binder::FunctionScope *scope, compiler::ProgramElement *programElement) -> void { + RegSpiller rspl; + ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + CodeGen cg(&allocator, &rspl, context, scope, programElement); + + FunctionEmitter funcEmitter(&cg, programElement); + funcEmitter.Generate(); + }; +} + +using EmitCb = std::function; + +template +static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const EmitCb &emitCb) +{ + ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + auto program = parser::Program::NewProgram(&allocator); + auto parser = Parser(&program, unit.options.stdLib, static_cast(unit.rawParserStatus)); + auto checker = Checker(); + + auto *binder = program.Binder(); + binder->SetProgram(&program); + + CompilerContext context(binder, &checker, unit.options, + MakeCompileJob()); + binder->SetCompilerContext(&context); + + auto emitter = Emitter(&context); + context.SetEmitter(&emitter); + + parser.ParseScript(unit.input); + + if (!checker.StartChecker(binder, unit.options)) { return nullptr; } - queue_->Schedule(context); + emitter.GenAnnotation(); - /* Main thread can also be used instead of idling */ - queue_->Consume(); - queue_->Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); + return emitCb(&context); +} - return emitter->Finalize(options.dumpDebugInfo); +pandasm::Program *CompilerImpl::Compile(const CompilationUnit &unit) +{ + auto emitCb = [this](CompilerContext *context) -> pandasm::Program * { return Emit(context); }; + + switch (unit.ext) { + case ScriptExtension::TS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::AS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::STS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::JS: { + return CreateCompiler( + unit, emitCb); + } + default: { + UNREACHABLE(); + return nullptr; + } + } } void CompilerImpl::DumpAsm(const panda::pandasm::Program *prog) diff --git a/compiler/core/compilerImpl.h b/compiler/core/compilerImpl.h index c81d92061..35cdf0b3d 100644 --- a/compiler/core/compilerImpl.h +++ b/compiler/core/compilerImpl.h @@ -17,6 +17,7 @@ #define ES2PANDA_COMPILER_INCLUDE_COMPILER_IMPL_H #include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" #include "macros.h" #include "mem/arena_allocator.h" #include "os/thread.h" @@ -35,19 +36,34 @@ namespace panda::es2panda::compiler { class CompileQueue; class CompilerContext; +class CompilationUnit { +public: + explicit CompilationUnit(const SourceFile &i, const CompilerOptions &o, uint32_t s, ScriptExtension e) + : input(i), options(o), rawParserStatus(s), ext(e) + { + } + const SourceFile &input; + const CompilerOptions &options; + uint32_t rawParserStatus; + ScriptExtension ext; +}; + class CompilerImpl { public: - explicit CompilerImpl(size_t threadCount); - ~CompilerImpl(); + explicit CompilerImpl(size_t threadCount) : queue_(threadCount) {} NO_COPY_SEMANTIC(CompilerImpl); NO_MOVE_SEMANTIC(CompilerImpl); + ~CompilerImpl() = default; + + pandasm::Program *Compile(const CompilationUnit &unit); - panda::pandasm::Program *Compile(CompilerContext *context, parser::Program *program, - const es2panda::CompilerOptions &options); static void DumpAsm(const panda::pandasm::Program *prog); private: - CompileQueue *queue_; + panda::pandasm::Program *Emit(CompilerContext *context); + static void HandleContextLiterals(CompilerContext *context); + + CompileQueue queue_; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/dynamicContext.cpp b/compiler/core/dynamicContext.cpp index eb936f4b1..3e681ae81 100644 --- a/compiler/core/dynamicContext.cpp +++ b/compiler/core/dynamicContext.cpp @@ -17,30 +17,31 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" #include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/compiler/core/envScope.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/statements/tryStatement.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" #include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" namespace panda::es2panda::compiler { -DynamicContext::DynamicContext(PandaGen *pg, LabelTarget target) : pg_(pg), target_(target), prev_(pg_->dynamicContext_) +DynamicContext::DynamicContext(CodeGen *cg, LabelTarget target) : cg_(cg), target_(target), prev_(cg_->dynamicContext_) { - pg_->dynamicContext_ = this; + cg_->dynamicContext_ = this; } DynamicContext::~DynamicContext() { - pg_->dynamicContext_ = prev_; + cg_->dynamicContext_ = prev_; } -LabelContext::LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt) - : DynamicContext(pg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) +LabelContext::LabelContext(CodeGen *cg, const ir::LabelledStatement *labelledStmt) + : DynamicContext(cg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) { if (!labelledStmt->Body()->IsBlockStatement()) { return; } - label_ = pg->AllocLabel(); + label_ = cg->AllocLabel(); target_.SetBreakTarget(label_); } @@ -50,7 +51,7 @@ LabelContext::~LabelContext() return; } - pg_->SetLabel(labelledStmt_, label_); + cg_->SetLabel(labelledStmt_, label_); } LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget target) @@ -60,11 +61,11 @@ LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget t return; } - catchTable_ = pg_->CreateCatchTable(); + catchTable_ = cg_->CreateCatchTable(); const auto &labelSet = catchTable_->LabelSet(); const auto *node = envScope_->Scope()->Node(); - pg_->SetLabel(node, labelSet.TryBegin()); + cg_->SetLabel(node, labelSet.TryBegin()); } LexEnvContext::~LexEnvContext() @@ -76,14 +77,19 @@ LexEnvContext::~LexEnvContext() const auto &labelSet = catchTable_->LabelSet(); const auto *node = envScope_->Scope()->Node(); - pg_->SetLabel(node, labelSet.TryEnd()); - pg_->Branch(node, labelSet.CatchEnd()); + cg_->SetLabel(node, labelSet.TryEnd()); + cg_->Branch(node, labelSet.CatchEnd()); - pg_->SetLabel(node, labelSet.CatchBegin()); - pg_->PopLexEnv(node); - pg_->EmitThrow(node); - pg_->SetLabel(node, labelSet.CatchEnd()); - pg_->PopLexEnv(node); + cg_->SetLabel(node, labelSet.CatchBegin()); + AsPandaGen()->PopLexEnv(node); + AsPandaGen()->EmitThrow(node); + cg_->SetLabel(node, labelSet.CatchEnd()); + AsPandaGen()->PopLexEnv(node); +} + +PandaGen *LexEnvContext::AsPandaGen() const +{ + return static_cast(cg_); } bool LexEnvContext::HasTryCatch() const @@ -99,14 +105,14 @@ void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, } const auto *node = envScope_->Scope()->Node(); - pg_->PopLexEnv(node); + AsPandaGen()->PopLexEnv(node); } IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target) : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable()) { const auto &labelSet = catchTable_->LabelSet(); - pg_->SetLabel(iterator_.Node(), labelSet.TryBegin()); + pg->SetLabel(iterator_.Node(), labelSet.TryBegin()); } IteratorContext::~IteratorContext() @@ -114,12 +120,12 @@ IteratorContext::~IteratorContext() const auto &labelSet = catchTable_->LabelSet(); const auto *node = iterator_.Node(); - pg_->SetLabel(node, labelSet.TryEnd()); - pg_->Branch(node, labelSet.CatchEnd()); + cg_->SetLabel(node, labelSet.TryEnd()); + cg_->Branch(node, labelSet.CatchEnd()); - pg_->SetLabel(node, labelSet.CatchBegin()); + cg_->SetLabel(node, labelSet.CatchBegin()); iterator_.Close(true); - pg_->SetLabel(node, labelSet.CatchEnd()); + cg_->SetLabel(node, labelSet.CatchEnd()); } void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, @@ -140,16 +146,19 @@ void TryContext::InitFinalizer() return; } - finalizerRun_ = pg_->AllocReg(); - pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED); + auto *pg = static_cast(cg_); + + finalizerRun_ = pg->AllocReg(); + pg->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED); } -void TryContext::InitCatchTable() +void CatchContext::InitCatchTable() { - catchTable_ = pg_->CreateCatchTable(); + auto *pg = static_cast(cg_); + catchTable_ = pg->CreateCatchTable(); } -const TryLabelSet &TryContext::LabelSet() const +const TryLabelSet &CatchContext::LabelSet() const { return catchTable_->LabelSet(); } @@ -165,14 +174,10 @@ void TryContext::EmitFinalizer() return; } + auto *pg = static_cast(cg_); inFinalizer_ = true; - tryStmt_->FinallyBlock()->Compile(pg_); + tryStmt_->FinallyBlock()->Compile(pg); inFinalizer_ = false; } -void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, - [[maybe_unused]] const util::StringView &targetLabel) -{ - EmitFinalizer(); -} } // namespace panda::es2panda::compiler diff --git a/compiler/core/dynamicContext.h b/compiler/core/dynamicContext.h index 44753babd..b3179ad6e 100644 --- a/compiler/core/dynamicContext.h +++ b/compiler/core/dynamicContext.h @@ -28,12 +28,12 @@ class LabelledStatement; } // namespace panda::es2panda::ir namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class LoopEnvScope; class CatchTable; class TryLabelSet; -enum class DynamicContextType { NONE, LABEL, LEX_ENV, ITERATOR, TRY }; +enum class DynamicContextType { NONE, LABEL, LEX_ENV, ITERATOR, TRY, TRAP }; class DynamicContext { public: @@ -75,10 +75,10 @@ public: } protected: - explicit DynamicContext(PandaGen *pg, LabelTarget target); + explicit DynamicContext(CodeGen *cg, LabelTarget target); // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - PandaGen *pg_; + CodeGen *cg_; LabelTarget target_; DynamicContext *prev_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -86,8 +86,8 @@ protected: class LabelContext : public DynamicContext { public: - explicit LabelContext(PandaGen *pg, LabelTarget target) : DynamicContext(pg, target) {} - explicit LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt); + explicit LabelContext(CodeGen *cg, LabelTarget target) : DynamicContext(cg, target) {} + explicit LabelContext(CodeGen *cg, const ir::LabelledStatement *labelledStmt); NO_COPY_SEMANTIC(LabelContext); NO_MOVE_SEMANTIC(LabelContext); ~LabelContext(); @@ -118,6 +118,9 @@ public: void AbortContext([[maybe_unused]] ControlFlowChange cfc, [[maybe_unused]] const util::StringView &targetLabel) override; +protected: + PandaGen *AsPandaGen() const; + private: LoopEnvScope *envScope_; CatchTable *catchTable_ {}; @@ -153,20 +156,47 @@ private: CatchTable *catchTable_; }; -class TryContext : public DynamicContext { +class CatchContext : public DynamicContext { public: - explicit TryContext(PandaGen *pg, const ir::TryStatement *tryStmt, bool hasFinalizer = true) - : DynamicContext(pg, {}), tryStmt_(tryStmt), hasFinalizer_(hasFinalizer) + NO_COPY_SEMANTIC(CatchContext); + NO_MOVE_SEMANTIC(CatchContext); + ~CatchContext() = default; + + CatchTable *GetCatchTable() const { - InitCatchTable(); - InitFinalizer(); + return catchTable_; + } + + const TryLabelSet &LabelSet() const; + + bool HasTryCatch() const override + { + return true; } - explicit TryContext(PandaGen *pg) : DynamicContext(pg, {}) +protected: + explicit CatchContext(CodeGen *cg) : DynamicContext(cg, {}) { InitCatchTable(); } + CatchTable *catchTable_ {}; + +private: + void InitCatchTable(); +}; + +class TryContext : public CatchContext { +public: + explicit TryContext(CodeGen *cg, const ir::TryStatement *tryStmt, bool hasFinalizer = true) + : CatchContext(cg), tryStmt_(tryStmt), hasFinalizer_(hasFinalizer) + + { + InitFinalizer(); + } + + explicit TryContext(CodeGen *cg) : CatchContext(cg) {} + NO_COPY_SEMANTIC(TryContext); NO_MOVE_SEMANTIC(TryContext); ~TryContext() = default; @@ -176,38 +206,51 @@ public: return DynamicContextType::TRY; } - bool HasTryCatch() const override - { - return true; - } - VReg FinalizerRun() const { return finalizerRun_; } - CatchTable *GetCatchTable() const - { - return catchTable_; - } - - const TryLabelSet &LabelSet() const; bool HasFinalizer() const override; void InitFinalizer(); void EmitFinalizer(); void AbortContext([[maybe_unused]] ControlFlowChange cfc, - [[maybe_unused]] const util::StringView &targetLabel) override; + [[maybe_unused]] const util::StringView &targetLabel) override + { + EmitFinalizer(); + } private: - void InitCatchTable(); - const ir::TryStatement *tryStmt_ {}; - CatchTable *catchTable_ {}; VReg finalizerRun_ {}; bool hasFinalizer_ {}; bool inFinalizer_ {}; }; + +class TrapContext : public CatchContext { +public: + explicit TrapContext(CodeGen *cg) : CatchContext(cg) {} + + NO_COPY_SEMANTIC(TrapContext); + NO_MOVE_SEMANTIC(TrapContext); + ~TrapContext() = default; + + DynamicContextType Type() const override + { + return DynamicContextType::TRAP; + } + + bool HasTryCatch() const override + { + return true; + } + + bool HasFinalizer() const override + { + return false; + } +}; } // namespace panda::es2panda::compiler #endif diff --git a/compiler/core/emitter.cpp b/compiler/core/emitter.cpp index bb01bd1d3..49d8c0598 100644 --- a/compiler/core/emitter.cpp +++ b/compiler/core/emitter.cpp @@ -15,22 +15,20 @@ #include "emitter.h" -#include "plugins/ecmascript/es2panda/ir/irnode.h" -#include "plugins/ecmascript/es2panda/binder/binder.h" #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/compiler/base/literals.h" #include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/regSpiller.h" #include "plugins/ecmascript/es2panda/compiler/debugger/debuginfoDumper.h" #include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" #include "plugins/ecmascript/es2panda/es2panda.h" -#include "generated/isa.h" -#include "plugins/ecmascript/es2panda/ir/expressions/literal.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "generated/isa.h" +#include "macros.h" #include #include @@ -108,33 +106,19 @@ static LiteralPair TransformLiteral(const compiler::Literal *literal) return {tagLit, valueLit}; } -constexpr const auto LANG_EXT = pandasm::extensions::Language::ECMASCRIPT; - void FunctionEmitter::Generate() { - auto *func = new panda::pandasm::Function(pg_->InternalName().Mutf8(), LANG_EXT); - programElement_->func = func; - - size_t paramCount = pg_->InternalParamCount(); - func->params.reserve(paramCount); - - for (uint32_t i = 0; i < paramCount; ++i) { - func->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT); - } - - func->regs_num = IRNode::REG_START - pg_->TotalRegsNum(); - func->return_type = panda::pandasm::Type("any", 0); - + auto *func = GenFunctionSignature(); GenFunctionInstructions(func); GenVariablesDebugInfo(func); GenSourceFileDebugInfo(func); GenFunctionCatchTables(func); - GenFunctionICSize(func); + GenFunctionAnnotations(func); } util::StringView FunctionEmitter::SourceCode() const { - return pg_->Binder()->Program()->SourceCode(); + return cg_->Binder()->Program()->SourceCode(); } static Format MatchFormat(const IRNode *node, const Formats &formats) @@ -155,8 +139,7 @@ static Format MatchFormat(const IRNode *node, const Formats &formats) } } - if (std::all_of(registers.begin(), registers.end(), - [limit](const VReg *reg) { return *reg >= IRNode::REG_START - limit; })) { + if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return reg->IsValid(limit); })) { return format; } } @@ -194,7 +177,7 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p ASSERT(astNode != nullptr); if (astNode == FIRST_NODE_OF_FUNCTION) { - astNode = pg_->Debuginfo().firstStmt; + astNode = cg_->Debuginfo().firstStmt; if (astNode == nullptr) { return; } @@ -202,7 +185,7 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p pandaIns->ins_debug.line_number = astNode->Range().start.line + 1; - if (pg_->IsDebug()) { + if (cg_->IsDebug()) { size_t insLen = GetIRNodeWholeLength(ins); if (insLen != 0) { pandaIns->ins_debug.bound_left = offset_; @@ -214,13 +197,13 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p } } -void FunctionEmitter::GenFunctionInstructions(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionInstructions(pandasm::Function *func) { - func->ins.reserve(pg_->Insns().size()); + func->ins.reserve(cg_->Insns().size()); - uint32_t totalRegs = pg_->TotalRegsNum(); + uint32_t totalRegs = cg_->TotalRegsNum(); - for (const auto *ins : pg_->Insns()) { + for (const auto *ins : cg_->Insns()) { auto &pandaIns = func->ins.emplace_back(); ins->Transform(&pandaIns, programElement_, totalRegs); @@ -228,32 +211,32 @@ void FunctionEmitter::GenFunctionInstructions(panda::pandasm::Function *func) } } -void FunctionEmitter::GenFunctionICSize(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionAnnotations(pandasm::Function *func) { pandasm::AnnotationData funcAnnotationData("_ESAnnotation"); pandasm::AnnotationElement icSizeAnnotationElement( "icSize", - std::make_unique(pandasm::ScalarValue::Create(pg_->IcSize()))); + std::make_unique(pandasm::ScalarValue::Create(cg_->IcSize()))); funcAnnotationData.AddElement(std::move(icSizeAnnotationElement)); pandasm::AnnotationElement parameterLengthAnnotationElement( "parameterLength", std::make_unique( - pandasm::ScalarValue::Create(pg_->FormalParametersCount()))); + pandasm::ScalarValue::Create(cg_->FormalParametersCount()))); funcAnnotationData.AddElement(std::move(parameterLengthAnnotationElement)); pandasm::AnnotationElement funcNameAnnotationElement( "funcName", std::make_unique( - pandasm::ScalarValue::Create(pg_->FunctionName().Mutf8()))); + pandasm::ScalarValue::Create(cg_->FunctionName().Mutf8()))); funcAnnotationData.AddElement(std::move(funcNameAnnotationElement)); func->metadata->AddAnnotations({funcAnnotationData}); } -void FunctionEmitter::GenFunctionCatchTables(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionCatchTables(pandasm::Function *func) { - func->catch_blocks.reserve(pg_->CatchList().size()); + func->catch_blocks.reserve(cg_->CatchList().size()); - for (const auto *catchBlock : pg_->CatchList()) { + for (const auto *catchBlock : cg_->CatchList()) { const auto &labelSet = catchBlock->LabelSet(); auto &pandaCatchBlock = func->catch_blocks.emplace_back(); @@ -264,31 +247,20 @@ void FunctionEmitter::GenFunctionCatchTables(panda::pandasm::Function *func) } } -void FunctionEmitter::GenSourceFileDebugInfo(panda::pandasm::Function *func) +void FunctionEmitter::GenSourceFileDebugInfo(pandasm::Function *func) { - func->source_file = std::string {pg_->Binder()->Program()->SourceFile()}; + func->source_file = std::string {cg_->Binder()->Program()->SourceFile()}; - if (!pg_->IsDebug()) { + if (!cg_->IsDebug()) { return; } - if (pg_->RootNode()->IsProgram()) { + if (cg_->RootNode()->IsProgram()) { func->source_code = SourceCode().EscapeSymbol(); } } -static void GenLocalVariableInfo(pandasm::debuginfo::LocalVariable &variableDebug, binder::Variable *var, - uint32_t start, uint32_t varsLength, uint32_t totalRegsNum) -{ - variableDebug.name = var->Name().Mutf8(); - variableDebug.signature = "any"; - variableDebug.signature_type = "any"; - variableDebug.reg = static_cast(IRNode::MapRegister(var->AsLocalVariable()->Vreg(), totalRegsNum)); - variableDebug.start = start; - variableDebug.length = static_cast(varsLength); -} - -void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const binder::Scope *scope) const +void FunctionEmitter::GenScopeVariableInfo(pandasm::Function *func, const binder::Scope *scope) const { const auto *startIns = scope->ScopeStart(); const auto *endIns = scope->ScopeEnd(); @@ -296,7 +268,7 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const uint32_t start = 0; uint32_t count = 0; - for (const auto *it : pg_->Insns()) { + for (const auto *it : cg_->Insns()) { if (startIns == it) { start = count; } else if (endIns == it) { @@ -309,15 +281,20 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const } } - for (const auto &[_, variable] : scope->Bindings()) { - (void)_; + for (const auto &[name, variable] : scope->Bindings()) { if (!variable->IsLocalVariable() || variable->LexicalBound() || variable->Declaration()->IsParameterDecl()) { continue; } auto &variableDebug = func->local_variable_debug.emplace_back(); - GenLocalVariableInfo(variableDebug, variable, start, varsLength, pg_->TotalRegsNum()); + variableDebug.name = name.Mutf8(); + // variableDebug.signature = "any"; + // variableDebug.signature_type = "any"; + GenVariableSignature(variableDebug, variable->AsLocalVariable()); + variableDebug.reg = static_cast(variable->AsLocalVariable()->Vreg().GetIndex()); + variableDebug.start = start; + variableDebug.length = static_cast(varsLength); } break; @@ -327,27 +304,23 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const } } -void FunctionEmitter::GenVariablesDebugInfo(panda::pandasm::Function *func) +void FunctionEmitter::GenVariablesDebugInfo(pandasm::Function *func) { - if (!pg_->IsDebug()) { + if (!cg_->IsDebug()) { return; } - for (const auto *scope : pg_->Debuginfo().variableDebugInfo) { + for (const auto *scope : cg_->Debuginfo().variableDebugInfo) { GenScopeVariableInfo(func, scope); } } // Emitter -Emitter::Emitter(const CompilerContext *context) +Emitter::Emitter(const CompilerContext *context) : context_(context) { prog_ = new pandasm::Program(); - prog_->lang = pandasm::extensions::Language::ECMASCRIPT; - prog_->function_table.reserve(context->Binder()->Functions().size()); - GenESAnnoatationRecord(); - GenESModuleModeRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); } Emitter::~Emitter() @@ -355,31 +328,7 @@ Emitter::~Emitter() delete prog_; } -void Emitter::GenESAnnoatationRecord() -{ - auto annotationRecord = pandasm::Record("_ESAnnotation", LANG_EXT); - annotationRecord.metadata->SetAttribute("external"); - annotationRecord.metadata->SetAccessFlags(ACC_ANNOTATION); - prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); -} - -void Emitter::GenESModuleModeRecord(bool isModule) -{ - auto modeRecord = pandasm::Record("_ESModuleMode", LANG_EXT); - modeRecord.metadata->SetAccessFlags(ACC_PUBLIC); - - auto modeField = pandasm::Field(LANG_EXT); - modeField.name = "isModule"; - modeField.type = pandasm::Type("u8", 0); - modeField.metadata->SetValue( - pandasm::ScalarValue::Create(static_cast(isModule))); - - modeRecord.field_list.emplace_back(std::move(modeField)); - - prog_->record_table.emplace(modeRecord.name, std::move(modeRecord)); -} - -static void UpdateLiteralBufferId(panda::pandasm::Ins *ins, uint32_t offset) +static void UpdateLiteralBufferId(pandasm::Ins *ins, uint32_t offset) { switch (ins->opcode) { case pandasm::Opcode::ECMA_DEFINECLASSWITHBUFFER: { diff --git a/compiler/core/emitter.h b/compiler/core/emitter.h index 64f61251b..c1f1f28aa 100644 --- a/compiler/core/emitter.h +++ b/compiler/core/emitter.h @@ -13,12 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_IR_EMITTER_H -#define ES2PANDA_COMPILER_IR_EMITTER_H +#ifndef ES2PANDA_COMPILER_CORE_EMITTER_H +#define ES2PANDA_COMPILER_CORE_EMITTER_H #include "plugins/ecmascript/es2panda/compiler/base/literals.h" -#include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include @@ -32,29 +30,29 @@ namespace panda::pandasm { struct Program; struct Function; struct Ins; +namespace debuginfo { +struct LocalVariable; +} // namespace debuginfo } // namespace panda::pandasm -namespace panda::es2panda::ir { -class Statement; -class Literal; -} // namespace panda::es2panda::ir - namespace panda::es2panda::binder { class Scope; +class LocalVariable; } // namespace panda::es2panda::binder namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class DebugInfo; class Label; class IRNode; class CompilerContext; class ProgramElement; +class RegSpiller; class FunctionEmitter { public: - explicit FunctionEmitter(const PandaGen *pg, ProgramElement *programElement) - : pg_(pg), programElement_(programElement) + explicit FunctionEmitter(const CodeGen *cg, ProgramElement *programElement) + : cg_(cg), programElement_(programElement) { } @@ -64,44 +62,48 @@ public: void Generate(); -private: +protected: + virtual pandasm::Function *GenFunctionSignature() = 0; + virtual void GenFunctionAnnotations(pandasm::Function *func) = 0; + virtual void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const = 0; + void GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns); - void GenFunctionInstructions(panda::pandasm::Function *func); + void GenFunctionInstructions(pandasm::Function *func); + void GenScopeVariableInfo(pandasm::Function *func, const binder::Scope *scope) const; + void GenSourceFileDebugInfo(pandasm::Function *func); void GenFunctionCatchTables(panda::pandasm::Function *func); - void GenFunctionICSize(panda::pandasm::Function *func); - void GenScopeVariableInfo(panda::pandasm::Function *func, const binder::Scope *scope) const; - void GenSourceFileDebugInfo(panda::pandasm::Function *func); - void GenVariablesDebugInfo(panda::pandasm::Function *func); + void GenVariablesDebugInfo(pandasm::Function *func); util::StringView SourceCode() const; - const PandaGen *pg_; + const CodeGen *cg_; ProgramElement *programElement_; size_t offset_ {0}; }; class Emitter { public: - explicit Emitter(const CompilerContext *context); - ~Emitter(); + virtual ~Emitter(); NO_COPY_SEMANTIC(Emitter); NO_MOVE_SEMANTIC(Emitter); - void AddFunction(FunctionEmitter *func); void AddLiteralBuffer(const LiteralBuffer &literals, uint32_t index); void AddProgramElement(ProgramElement *programElement); - static void DumpAsm(const panda::pandasm::Program *prog); - panda::pandasm::Program *Finalize(bool dumpDebugInfo); + static void DumpAsm(const pandasm::Program *prog); + pandasm::Program *Finalize(bool dumpDebugInfo); uint32_t &LiteralBufferIndex() { return literalBufferIndex_; } -private: - void GenESAnnoatationRecord(); - void GenESModuleModeRecord(bool isModule); + virtual void GenAnnotation() = 0; + +protected: + explicit Emitter(const CompilerContext *context); - panda::pandasm::Program *prog_; + pandasm::Program *prog_; + const CompilerContext *context_; uint32_t literalBufferIndex_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/envScope.cpp b/compiler/core/envScope.cpp index 6dd355c88..2b9b849e8 100644 --- a/compiler/core/envScope.cpp +++ b/compiler/core/envScope.cpp @@ -15,18 +15,19 @@ #include "envScope.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" #include "plugins/ecmascript/es2panda/ir/statement.h" namespace panda::es2panda::compiler { -ScopeContext::ScopeContext(PandaGen *pg, binder::Scope *newScope) : pg_(pg), prevScope_(pg_->scope_) +ScopeContext::ScopeContext(CodeGen *cg, binder::Scope *newScope) : cg_(cg), prevScope_(cg_->scope_) { - pg_->scope_ = newScope; + cg->scope_ = newScope; } ScopeContext::~ScopeContext() { - pg_->scope_ = prevScope_; + cg_->scope_ = prevScope_; } void EnvScope::Initialize(PandaGen *pg, VReg lexEnv) diff --git a/compiler/core/envScope.h b/compiler/core/envScope.h index ce0548c03..7de54780b 100644 --- a/compiler/core/envScope.h +++ b/compiler/core/envScope.h @@ -32,14 +32,14 @@ class PandaGen; class ScopeContext { public: - explicit ScopeContext(PandaGen *pg, binder::Scope *newScope); + explicit ScopeContext(CodeGen *cg, binder::Scope *newScope); ~ScopeContext(); NO_COPY_SEMANTIC(ScopeContext); NO_MOVE_SEMANTIC(ScopeContext); private: - PandaGen *pg_; + CodeGen *cg_; binder::Scope *prevScope_; }; diff --git a/compiler/core/function.cpp b/compiler/core/function.cpp index 17d8c1d27..8a31670d3 100644 --- a/compiler/core/function.cpp +++ b/compiler/core/function.cpp @@ -71,7 +71,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu uint32_t index = 0; for (const auto *param : func->Params()) { - LReference ref = LReference::CreateLRef(pg, param, true); + auto ref = JSLReference::Create(pg, param, true); [[maybe_unused]] binder::Variable *paramVar = ref.Variable(); @@ -82,7 +82,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu ASSERT(paramVar && paramVar->IsLocalVariable()); - VReg paramReg = binder::Binder::MANDATORY_PARAMS_NUMBER + IRNode::PARAM_START + index++; + VReg paramReg = VReg(binder::Binder::MANDATORY_PARAMS_NUMBER + VReg::PARAM_START + index++); ASSERT(paramVar->LexicalBound() || paramVar->AsLocalVariable()->Vreg() == paramReg); if (param->IsAssignmentPattern()) { @@ -175,11 +175,11 @@ void Function::CompileInstanceFields(PandaGen *pg, const ir::ScriptFunction *dec const auto *prop = element->AsClassProperty(); - if ((prop->Modifiers() & ir::ModifierFlags::STATIC) != 0) { + if ((prop->IsStatic())) { continue; } - if (prop->IsPrivate()) { + if (prop->IsPrivateElement()) { if (prop->Value() == nullptr) { pg->LoadConst(element, Constant::JS_UNDEFINED); } else { diff --git a/compiler/core/labelTarget.cpp b/compiler/core/labelTarget.cpp index f8b39bbc6..b5cb85866 100644 --- a/compiler/core/labelTarget.cpp +++ b/compiler/core/labelTarget.cpp @@ -15,11 +15,11 @@ #include "labelTarget.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" namespace panda::es2panda::compiler { -LabelTarget::LabelTarget(PandaGen *pg) - : LabelPair(pg->AllocLabel(), pg->AllocLabel()), breakLabel_(BREAK_LABEL), continueLabel_(CONTINUE_LABEL) +LabelTarget::LabelTarget(CodeGen *cg) + : LabelPair(cg->AllocLabel(), cg->AllocLabel()), breakLabel_(BREAK_LABEL), continueLabel_(CONTINUE_LABEL) { } } // namespace panda::es2panda::compiler diff --git a/compiler/core/labelTarget.h b/compiler/core/labelTarget.h index e31db8f01..870d37b66 100644 --- a/compiler/core/labelTarget.h +++ b/compiler/core/labelTarget.h @@ -28,7 +28,7 @@ class Identifier; namespace panda::es2panda::compiler { class LabelTarget; -class PandaGen; +class CodeGen; enum class ControlFlowChange { CONTINUE, @@ -37,7 +37,7 @@ enum class ControlFlowChange { class LabelTarget : public LabelPair { public: - explicit LabelTarget(PandaGen *pg); + explicit LabelTarget(CodeGen *cg); explicit LabelTarget(const util::StringView &label) : LabelTarget(nullptr, label) {} explicit LabelTarget(Label *target, const util::StringView &label) : LabelPair(target, nullptr), breakLabel_(label), continueLabel_(label) diff --git a/compiler/core/pandagen.cpp b/compiler/core/pandagen.cpp index 6ff9b530d..bb9297025 100644 --- a/compiler/core/pandagen.cpp +++ b/compiler/core/pandagen.cpp @@ -39,59 +39,6 @@ #include "plugins/ecmascript/es2panda/ir/expressions/literals/stringLiteral.h" namespace panda::es2panda::compiler { -// PandaGen - -Label *PandaGen::AllocLabel() -{ - std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++); - return sa_.AllocLabel(std::move(id)); -} - -bool PandaGen::IsDebug() const -{ - return context_->IsDebug(); -} - -uint32_t PandaGen::ParamCount() const -{ - if (rootNode_->IsProgram()) { - return IsDirectEval() ? 1 : 0; - } - - return rootNode_->AsScriptFunction()->Params().size(); -} - -uint32_t PandaGen::FormalParametersCount() const -{ - if (rootNode_->IsProgram()) { - return 0; - } - - ASSERT(rootNode_->IsScriptFunction()); - - return rootNode_->AsScriptFunction()->FormalParamsLength(); -} - -uint32_t PandaGen::InternalParamCount() const -{ - static const uint32_t HIDDEN_PARAMS = 3; - return ParamCount() + HIDDEN_PARAMS; -} - -const util::StringView &PandaGen::InternalName() const -{ - return topScope_->InternalName(); -} - -const util::StringView &PandaGen::FunctionName() const -{ - return topScope_->Name(); -} - -binder::Binder *PandaGen::Binder() const -{ - return context_->Binder(); -} void PandaGen::FunctionInit(CatchTable *catchTable) { @@ -102,7 +49,7 @@ void PandaGen::FunctionInit(CatchTable *catchTable) const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); - if (func->IsAsync()) { + if (func->IsAsyncFunc()) { if (func->IsGenerator()) { builder_ = allocator_->New(this, catchTable); return; @@ -128,7 +75,7 @@ bool PandaGen::FunctionHasFinalizer() const const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); - return func->IsAsync() || func->IsGenerator(); + return func->IsAsyncFunc() || func->IsGenerator(); } void PandaGen::FunctionEnter() @@ -141,10 +88,85 @@ void PandaGen::FunctionExit() builder_->CleanUp(rootNode_->AsScriptFunction()); } -int32_t PandaGen::AddLiteralBuffer(LiteralBuffer &&buf) +void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg) { - programElement_->buffStorage.emplace_back(std::move(buf)); - return literalBufferIdx_++; + ra_.Emit(node, vreg); +} + +void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg) +{ + ra_.Emit(node, reg); +} + +void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs) +{ + ra_.Emit(node, vd, vs); +} + +void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num) +{ + sa_.Emit(node, num); +} + +void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num) +{ + sa_.Emit(node, num); +} + +void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) +{ + sa_.Emit(node, static_cast(num)); +} + +void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) +{ + LoadConst(node, id); + StoreAccumulator(node, reg); +} + +void PandaGen::LoadConst(const ir::AstNode *node, Constant id) +{ + switch (id) { + case Constant::JS_HOLE: { + sa_.Emit(node); + break; + } + case Constant::JS_NAN: { + sa_.Emit(node); + break; + } + case Constant::JS_INFINITY: { + sa_.Emit(node); + break; + } + case Constant::JS_GLOBAL: { + sa_.Emit(node); + break; + } + case Constant::JS_UNDEFINED: { + sa_.Emit(node); + break; + } + case Constant::JS_SYMBOL: { + sa_.Emit(node); + break; + } + case Constant::JS_NULL: { + sa_.Emit(node); + break; + } + case Constant::JS_TRUE: { + sa_.Emit(node); + break; + } + case Constant::JS_FALSE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } } void PandaGen::GetFunctionObject(const ir::AstNode *node) @@ -217,16 +239,9 @@ void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult & StoreAccToLexEnv(node, result, isDeclaration); } -void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg) -{ - ra_.Emit(node, vreg); -} - void PandaGen::LoadAccFromArgs(const ir::AstNode *node) { - const auto *varScope = scope_->AsVariableScope(); - - if (!varScope->HasFlag(binder::VariableScopeFlags::USE_ARGS)) { + if (!scope_->HasFlag(binder::ScopeFlags::USE_ARGS)) { return; } @@ -345,11 +360,6 @@ void PandaGen::DeleteObjProperty(const ir::AstNode *node, VReg obj, VReg prop) ra_.Emit(node, obj, prop); } -void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg) -{ - ra_.Emit(node, reg); -} - void PandaGen::LoadGlobalVar(const ir::AstNode *node, const util::StringView &name) { sa_.Emit(node, name); @@ -375,163 +385,11 @@ void PandaGen::StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFind VirtualStoreVar::Expand(this, node, result, isDeclaration); } -void PandaGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str) -{ - sa_.Emit(node, str); -} - void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &bigInt) { sa_.Emit(node, bigInt); } -void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num) -{ - sa_.Emit(node, num); -} - -void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num) -{ - sa_.Emit(node, num); -} - -void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) -{ - sa_.Emit(node, static_cast(num)); -} - -void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) -{ - LoadConst(node, id); - StoreAccumulator(node, reg); -} - -void PandaGen::LoadConst(const ir::AstNode *node, Constant id) -{ - switch (id) { - case Constant::JS_HOLE: { - sa_.Emit(node); - break; - } - case Constant::JS_NAN: { - sa_.Emit(node); - break; - } - case Constant::JS_INFINITY: { - sa_.Emit(node); - break; - } - case Constant::JS_GLOBAL: { - sa_.Emit(node); - break; - } - case Constant::JS_UNDEFINED: { - sa_.Emit(node); - break; - } - case Constant::JS_SYMBOL: { - sa_.Emit(node); - break; - } - case Constant::JS_NULL: { - sa_.Emit(node); - break; - } - case Constant::JS_TRUE: { - sa_.Emit(node); - break; - } - case Constant::JS_FALSE: { - sa_.Emit(node); - break; - } - default: { - UNREACHABLE(); - } - } -} - -void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs) -{ - ra_.Emit(node, vd, vs); -} - -void PandaGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label) -{ - sa_.AddLabel(label); -} - -void PandaGen::Branch(const ir::AstNode *node, Label *label) -{ - sa_.Emit(node, label); -} - -bool PandaGen::CheckControlFlowChange() -{ - const auto *iter = dynamicContext_; - - while (iter != nullptr) { - if (iter->HasFinalizer()) { - return true; - } - - iter = iter->Prev(); - } - - return false; -} - -Label *PandaGen::ControlFlowChangeBreak(const ir::Identifier *label) -{ - auto *iter = dynamicContext_; - - util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::BREAK_LABEL; - Label *breakTarget = nullptr; - - while (iter != nullptr) { - iter->AbortContext(ControlFlowChange::BREAK, labelName); - - const auto &labelTargetName = iter->Target().BreakLabel(); - - if (iter->Target().BreakTarget() != nullptr) { - breakTarget = iter->Target().BreakTarget(); - } - - if (labelTargetName == labelName) { - break; - } - - iter = iter->Prev(); - } - - return breakTarget; -} - -Label *PandaGen::ControlFlowChangeContinue(const ir::Identifier *label) -{ - auto *iter = dynamicContext_; - util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::CONTINUE_LABEL; - Label *continueTarget = nullptr; - - while (iter != nullptr) { - iter->AbortContext(ControlFlowChange::CONTINUE, labelName); - - const auto &labelTargetName = iter->Target().ContinueLabel(); - - if (iter->Target().ContinueTarget() != nullptr) { - continueTarget = iter->Target().ContinueTarget(); - } - - if (labelTargetName == labelName) { - break; - } - - iter = iter->Prev(); - } - - return continueTarget; -} - void PandaGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse) { switch (op) { @@ -836,7 +694,7 @@ void PandaGen::Call1This(const ir::AstNode *node, VReg callee, VReg thisReg, VRe void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments) { - bool hasThis = thisReg != INVALID_VREG; + bool hasThis = !thisReg.IsInvalid(); switch (arguments.size()) { case 0: { // 0 args @@ -919,7 +777,7 @@ void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const Ar void PandaGen::CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments) { - bool hasThis = thisReg != INVALID_VREG; + bool hasThis = !thisReg.IsInvalid(); StoreAccumulator(node, callee); Literals::GetTemplateObject(this, node->AsTaggedTemplateExpression()); @@ -1012,7 +870,7 @@ void PandaGen::DefineMethod(const ir::AstNode *node, const util::StringView &nam void PandaGen::DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name) { - if (realNode->IsAsync()) { + if (realNode->IsAsyncFunc()) { if (realNode->IsGenerator()) { ra_.Emit(node, name, LexEnv()); } else { @@ -1342,7 +1200,7 @@ void PandaGen::GetAsyncIterator(const ir::AstNode *node) void PandaGen::CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount) { - ASSERT(argStart == obj - 1); + ASSERT(argStart.GetIndex() == obj.GetIndex() - 1); if (argCount == 0) { // Do not emit undefined register argStart = obj; } @@ -1529,38 +1387,9 @@ void PandaGen::LdLexEnv(const ir::AstNode *node) sa_.Emit(node); } -uint32_t PandaGen::TryDepth() const -{ - const auto *iter = dynamicContext_; - uint32_t depth = 0; - - while (iter != nullptr) { - if (iter->HasTryCatch()) { - depth++; - } - - iter = iter->Prev(); - } - - return depth; -} - -CatchTable *PandaGen::CreateCatchTable() -{ - auto *catchTable = allocator_->New(this, TryDepth()); - catchList_.push_back(catchTable); - return catchTable; -} - -void PandaGen::SortCatchTables() -{ - std::sort(catchList_.begin(), catchList_.end(), - [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); }); -} - Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed) { - VReg res {IRNode::REG_START}; + VReg res {VReg::REG_START}; if (!isComputed) { if (prop->IsIdentifier()) { @@ -1586,7 +1415,7 @@ Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed } if (prop->IsNumberLiteral()) { - auto num = prop->AsNumberLiteral()->Number(); + auto num = prop->AsNumberLiteral()->Number().GetDouble(); if (util::Helpers::IsIndex(num)) { return static_cast(num); } diff --git a/compiler/core/pandagen.h b/compiler/core/pandagen.h index 03b65f927..369943e6e 100644 --- a/compiler/core/pandagen.h +++ b/compiler/core/pandagen.h @@ -16,10 +16,11 @@ #ifndef ES2PANDA_COMPILER_CORE_PANDAGEN_H #define ES2PANDA_COMPILER_CORE_PANDAGEN_H -#include "plugins/ecmascript/es2panda/compiler/base/literals.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" #include "plugins/ecmascript/es2panda/compiler/base/optionalChain.h" #include "plugins/ecmascript/es2panda/compiler/core/envScope.h" -#include "plugins/ecmascript/es2panda/compiler/core/inlineCache.h" +#include "plugins/ecmascript/es2panda/compiler/core/function.h" + #include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" #include "plugins/ecmascript/es2panda/compiler/core/regScope.h" #include "plugins/ecmascript/es2panda/ir/irnode.h" @@ -46,115 +47,20 @@ namespace panda::es2panda::compiler { class FunctionBuilder; class CompilerContext; class DynamicContext; -class CatchTable; - -enum class Constant { - JS_NAN, - JS_HOLE, - JS_INFINITY, - JS_UNDEFINED, - JS_NULL, - JS_TRUE, - JS_FALSE, - JS_SYMBOL, - JS_GLOBAL, -}; - -class DebugInfo { -public: - explicit DebugInfo(ArenaAllocator *allocator) : variableDebugInfo(allocator->Adapter()) {}; - DEFAULT_COPY_SEMANTIC(DebugInfo); - DEFAULT_MOVE_SEMANTIC(DebugInfo); - ~DebugInfo() = default; - - // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - ArenaVector variableDebugInfo; - const ir::Statement *firstStmt {}; - // NOLINTEND(misc-non-private-member-variables-in-classes) -}; -class PandaGen { +class PandaGen : public CodeGen { public: - explicit PandaGen(ArenaAllocator *allocator, CompilerContext *context, binder::FunctionScope *scope, - ProgramElement *programElement) - : allocator_(allocator), - context_(context), - debugInfo_(allocator_), - topScope_(scope), - scope_(topScope_), - rootNode_(scope->Node()), - insns_(allocator_->Adapter()), - catchList_(allocator_->Adapter()), - programElement_(programElement), - sa_(this), - ra_(this), - rra_(this) + explicit PandaGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : CodeGen(allocator, spiller, context, scope, programElement) { + Function::Compile(this); } + ~PandaGen() = default; NO_COPY_SEMANTIC(PandaGen); NO_MOVE_SEMANTIC(PandaGen); - inline ArenaAllocator *Allocator() const - { - return allocator_; - } - - const ArenaVector &CatchList() const - { - return catchList_; - } - - binder::FunctionScope *TopScope() const - { - return topScope_; - } - - binder::Scope *Scope() const - { - return scope_; - } - - const ir::AstNode *RootNode() const - { - return rootNode_; - } - - ArenaList &Insns() - { - return insns_; - } - - const ArenaList &Insns() const - { - return insns_; - } - - VReg AllocReg() - { - return usedRegs_--; - } - - VReg NextReg() const - { - return usedRegs_; - } - - uint32_t TotalRegsNum() const - { - return totalRegs_; - } - - size_t LabelCount() const - { - return labelId_; - } - - const DebugInfo &Debuginfo() const - { - return debugInfo_; - } - FunctionBuilder *FuncBuilder() const { return builder_; @@ -172,21 +78,6 @@ public: } } - uint32_t IcSize() const - { - return ic_.Size(); - } - - bool IsDebug() const; - uint32_t ParamCount() const; - uint32_t FormalParametersCount() const; - uint32_t InternalParamCount() const; - const util::StringView &InternalName() const; - const util::StringView &FunctionName() const; - binder::Binder *Binder() const; - - Label *AllocLabel(); - VReg LexEnv() const; bool FunctionHasFinalizer() const; @@ -194,7 +85,16 @@ public: void FunctionEnter(); void FunctionExit(); - int32_t AddLiteralBuffer(LiteralBuffer &&buf); + void StoreAccumulator(const ir::AstNode *node, VReg vreg); + void LoadAccumulator(const ir::AstNode *node, VReg reg); + void MoveVreg(const ir::AstNode *node, VReg vd, VReg vs); + + void LoadAccumulatorFloat(const ir::AstNode *node, double num); + void LoadAccumulatorInt(const ir::AstNode *node, int32_t num); + void LoadAccumulatorInt(const ir::AstNode *node, size_t num); + + void LoadConst(const ir::AstNode *node, Constant id); + void StoreConst(const ir::AstNode *node, VReg reg, Constant id); void GetFunctionObject(const ir::AstNode *node); void GetNewTarget(const ir::AstNode *node); @@ -203,7 +103,6 @@ public: void LoadVar(const ir::Identifier *node, const binder::ScopeFindResult &result); void StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration); - void StoreAccumulator(const ir::AstNode *node, VReg vreg); void LoadAccFromArgs(const ir::AstNode *node); void LoadObjProperty(const ir::AstNode *node, const Operand &prop); @@ -212,7 +111,6 @@ public: void StoreObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop); void StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop); void DeleteObjProperty(const ir::AstNode *node, VReg obj, VReg prop); - void LoadAccumulator(const ir::AstNode *node, VReg reg); void LoadGlobalVar(const ir::AstNode *node, const util::StringView &name); void StoreGlobalVar(const ir::AstNode *node, const util::StringView &name); void StoreGlobalLet(const ir::AstNode *node, const util::StringView &name); @@ -225,21 +123,7 @@ public: void LoadAccFromLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result); void StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration); - void LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str); void LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &bigInt); - void LoadAccumulatorFloat(const ir::AstNode *node, double num); - void LoadAccumulatorInt(const ir::AstNode *node, int32_t num); - void LoadAccumulatorInt(const ir::AstNode *node, size_t num); - - void LoadConst(const ir::AstNode *node, Constant id); - void StoreConst(const ir::AstNode *node, VReg reg, Constant id); - void MoveVreg(const ir::AstNode *node, VReg vd, VReg vs); - - void SetLabel(const ir::AstNode *node, Label *label); - void Branch(const ir::AstNode *node, class Label *label); - bool CheckControlFlowChange(); - Label *ControlFlowChangeBreak(const ir::Identifier *label = nullptr); - Label *ControlFlowChangeContinue(const ir::Identifier *label); void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, class Label *ifFalse); void Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand); @@ -248,6 +132,7 @@ public: void BranchIfUndefined(const ir::AstNode *node, class Label *target); void BranchIfNotUndefined(const ir::AstNode *node, class Label *target); void BranchIfHole(const ir::AstNode *node, class Label *target); + void BranchIfTrue(const ir::AstNode *node, class Label *target); void BranchIfNotTrue(const ir::AstNode *node, class Label *target); void BranchIfFalse(const ir::AstNode *node, class Label *target); @@ -262,7 +147,6 @@ public: void ImplicitReturn(const ir::AstNode *node); void EmitAwait(const ir::AstNode *node); - static constexpr auto MAX_RANGE_CALL_ARG = 128; void CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments); void Call(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments); void Call0This(const ir::AstNode *node, VReg callee, VReg thisReg); @@ -369,10 +253,6 @@ public: void ThrowTdz(const ir::AstNode *node, const util::StringView &name); void ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name); - uint32_t TryDepth() const; - CatchTable *CreateCatchTable(); - void SortCatchTables(); - void LoadObjByIndex(const ir::AstNode *node, int64_t index); void LoadObjByValue(const ir::AstNode *node, VReg obj); @@ -397,52 +277,17 @@ public: bool IsDirectEval() const; bool IsEval() const; - void SetFirstStmt(const ir::Statement *stmt) - { - debugInfo_.firstStmt = stmt; - } - - [[noreturn]] static void Unimplemented() - { - throw Error(ErrorType::GENERIC, "Unimplemented code path"); - } - private: void LoadEvalBindings(const ir::AstNode *node); - ArenaAllocator *allocator_; - CompilerContext *context_; FunctionBuilder *builder_ {}; - DebugInfo debugInfo_; - binder::FunctionScope *topScope_; - binder::Scope *scope_; - const ir::AstNode *rootNode_; - ArenaList insns_; - ArenaVector catchList_; - ProgramElement *programElement_; - EnvScope *envScope_ {}; - DynamicContext *dynamicContext_ {}; OptionalChain *optionalChain_ {}; - InlineCache ic_; - SimpleAllocator sa_; - RegAllocator ra_; - RangeRegAllocator rra_; - - uint32_t usedRegs_ {IRNode::REG_START}; - uint32_t totalRegs_ {IRNode::REG_START}; - int32_t literalBufferIdx_ {0}; - friend class ScopeContext; - friend class RegScope; - friend class LocalRegScope; - friend class LoopRegScope; - friend class ParamRegScope; - friend class FunctionRegScope; + friend class EnvScope; friend class LoopEnvScope; friend class DynamicContext; friend class OptionalChain; - size_t labelId_ {0}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/inlineCache.h b/compiler/core/programElement.cpp similarity index 71% rename from compiler/core/inlineCache.h rename to compiler/core/programElement.cpp index fd6d602bc..ded115221 100644 --- a/compiler/core/inlineCache.h +++ b/compiler/core/programElement.cpp @@ -13,22 +13,13 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_IR_INLINE_CACHE_H -#define ES2PANDA_COMPILER_IR_INLINE_CACHE_H +#include "programElement.h" -#include "macros.h" +#include namespace panda::es2panda::compiler { -class InlineCache { -public: - explicit InlineCache() = default; - - size_t Size() const; - uint32_t Offset(uint32_t slotSize); - -private: - size_t size_ {}; -}; +ProgramElement::~ProgramElement() +{ + delete func; +} } // namespace panda::es2panda::compiler - -#endif diff --git a/compiler/core/programElement.h b/compiler/core/programElement.h new file mode 100644 index 000000000..5101c369d --- /dev/null +++ b/compiler/core/programElement.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_PROGRAM_ELEMENT_H +#define ES2PANDA_COMPILER_CORE_PROGRAM_ELEMENT_H + +#include "macros.h" +#include "plugins/ecmascript/es2panda/compiler/base/literals.h" + +namespace panda::pandasm { +struct Ins; +struct Function; +} // namespace panda::pandasm + +namespace panda::es2panda::compiler { +class ProgramElement { +public: + explicit ProgramElement() = default; + ~ProgramElement(); + NO_COPY_SEMANTIC(ProgramElement); + NO_MOVE_SEMANTIC(ProgramElement); + + std::unordered_set strings; + std::vector literalBufferIns; + std::vector buffStorage; + panda::pandasm::Function *func {}; +}; +} // namespace panda::es2panda::compiler +#endif diff --git a/compiler/core/regAllocator.cpp b/compiler/core/regAllocator.cpp index 13a408947..e95c6c7d4 100644 --- a/compiler/core/regAllocator.cpp +++ b/compiler/core/regAllocator.cpp @@ -15,70 +15,76 @@ #include "regAllocator.h" -#include "plugins/ecmascript/es2panda/ir/irnode.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" #include namespace panda::es2panda::compiler { -// RegAllocatorBase void AllocatorBase::PushBack(IRNode *ins) { - pg_->Insns().push_back(ins); + cg_->Insns().push_back(ins); } ArenaAllocator *AllocatorBase::Allocator() const { - return pg_->Allocator(); + return cg_->Allocator(); } // SimpleAllocator Label *SimpleAllocator::AllocLabel(std::string &&id) { - const auto *lastInsNode = pg_->Insns().empty() ? FIRST_NODE_OF_FUNCTION : pg_->Insns().back()->Node(); + const auto *lastInsNode = cg_->Insns().empty() ? FIRST_NODE_OF_FUNCTION : cg_->Insns().back()->Node(); return Alloc